Condividi tramite


Operatore di spostamento a destra senza segno

Nota

Questo articolo è una specifica di funzionalità. La specifica funge da documento di progettazione per la funzionalità. Include le modifiche specifiche proposte, insieme alle informazioni necessarie durante la progettazione e lo sviluppo della funzionalità. Questi articoli vengono pubblicati fino a quando le modifiche specifiche proposte non vengono completate e incorporate nella specifica ECMA corrente.

Potrebbero verificarsi alcune discrepanze tra la specifica di funzionalità e l'implementazione completata. Tali differenze vengono acquisite nelle note language design meeting (LDM) pertinenti.

Altre informazioni sul processo per l'adozione di speclet di funzionalità nello standard del linguaggio C# sono disponibili nell'articolo sulle specifiche di .

Problema del campione: https://github.com/dotnet/csharplang/issues/4682

Sommario

Un operatore di spostamento a destra senza segno sarà supportato da C# come operatore predefinito (per i tipi integrali primitivi) e come operatore definito dall'utente.

Motivazione

Quando si lavora con il valore integrale con segno, non è raro che sia necessario spostare i bit direttamente senza replicare il bit di ordine elevato in ogni turno. Anche se ciò può essere ottenuto per i tipi integrali primitivi con un operatore di spostamento regolare, è necessario eseguire un cast a un tipo senza segno prima dell'operazione di spostamento e un cast di ritorno al tipo originale dopo di essa. Nel contesto delle interfacce matematiche generiche che le librerie stanno pianificando di esporre, questo è potenzialmente più problematico poiché il tipo potrebbe non avere una controparte non segnata, definita o nota in anticipo dal codice matematico generico; tuttavia, un algoritmo potrebbe basarsi sulla capacità di effettuare un'operazione di spostamento a destra non segnata.

Progettazione dettagliata

Operatori e segni di punteggiatura

La sezione §6.4.6 verrà modificata per includere l'operatore >>> - l'operatore di spostamento a destra senza segno:

unsigned_right_shift
    : '>>>'
    ;

unsigned_right_shift_assignment
    : '>>>='
    ;

Non sono consentiti caratteri di alcun tipo (nemmeno spazi vuoti) tra i token nelle unsigned_right_shift e unsigned_right_shift_assignment produzioni. Queste produzioni vengono trattate appositamente per consentire la corretta gestione delle type_parameter_list.

Operatori di spostamento

La sezione §12.11 verrà modificata per includere l'operatore >>>, l'operatore di spostamento a destra senza segno:

Gli operatori <<, >> e >>> vengono usati per eseguire operazioni di spostamento dei bit.

shift_expression
    : additive_expression
    | shift_expression '<<' additive_expression
    | shift_expression right_shift additive_expression
    | shift_expression unsigned_right_shift additive_expression
    ;

Per un'operazione di forma x << count o x >> count o x >>> count, viene applicata la risoluzione dell'overload dell'operatore binario (§12.4.5) per selezionare un'implementazione specifica dell'operatore. Gli operandi vengono convertiti nei tipi di parametro dell'operatore selezionato e il tipo del risultato è il tipo restituito dell'operatore.

Gli operatori di spostamento senza segno predefiniti supporteranno lo stesso set di firme attualmente supportate dagli operatori di spostamento firmati predefiniti nell'implementazione corrente.

  • Sposta a destra:

    int operator >>>(int x, int count);
    uint operator >>>(uint x, int count);
    long operator >>>(long x, int count);
    ulong operator >>>(ulong x, int count);
    nint operator >>>(nint x, int count);
    nuint operator >>>(nuint x, int count);
    

    L'operatore >>> sposta x direttamente in base a un numero di bit calcolati come descritto di seguito.

    I bit di ordine basso di x vengono eliminati, i bit rimanenti vengono spostati a destra e le posizioni dei bit vuoti di ordine elevato vengono impostate su zero.

Per gli operatori predefiniti, il numero di bit da spostare viene calcolato come segue:

  • Quando il tipo di x è int o uint, il conteggio degli spostamenti è determinato dai cinque bit di basso ordine di count. In altre parole, il conteggio dei turni viene calcolato da count & 0x1F.
  • Quando il tipo di x è long o ulong, il conteggio dei bit di spostamento è determinato dai sei bit di ordine inferiore di count. In altre parole, il conteggio dei turni viene calcolato da count & 0x3F.

Se il conteggio dei turni risultante è zero, gli operatori di spostamento restituiscono semplicemente il valore di x.

Le operazioni di spostamento non causano mai overflow e producono gli stessi risultati nei contesti checked e unchecked.

Operatori di assegnazione

La sezione §12.21 verrà modificata in modo da includere unsigned_right_shift_assignment come indicato di seguito:

assignment_operator
    : '='
    | '+='
    | '-='
    | '*='
    | '/='
    | '%='
    | '&='
    | '|='
    | '^='
    | '<<='
    | right_shift_assignment
    | unsigned_right_shift_assignment
    ;

Tipi integrali

I tipi integrali sezione 8.3.6 verranno modificati in modo da includere informazioni sull'operatore >>>. Il punto elenco pertinente è il seguente:

  • Per gli operatori binari <<, >> e >>>, l'operando sinistro viene convertito nel tipo T, dove T è il primo di int, uint, longe ulong che può rappresentare completamente tutti i valori possibili dell'operando. L'operazione viene quindi eseguita utilizzando la precisione del tipo Te il tipo del risultato è T.

Espressioni costanti

L'operatore >>> verrà aggiunto al set di costrutti consentiti nelle espressioni costanti in §12.23.

Sovraccarico degli operatori

L'operatore >>> verrà aggiunto all'insieme di operatori binari sovraccaricabili a §12.4.3.

Operatori elevati

L'operatore >>> verrà aggiunto all'insieme di operatori binari che consente una forma elevata in §12.4.8.

Precedenza e associatività degli operatori

La sezione §12.4.2 verrà modificata per aggiungere l'operatore >>> alla categoria "Shift" e l'operatore >>>= alla categoria "Assegnazione ed espressione lambda".

Ambiguità grammaticali

L'operatore >>> è soggetto alle stesse ambiguità grammaticali descritte in §6.2.5 come operatore >> regolare.

Operatori

La sezione §15.10 verrà modificata per includere l'operatore >>>.

overloadable_binary_operator
    : '+'   | '-'   | '*'   | '/'   | '%'   | '&'   | '|'   | '^'   | '<<'
    | right_shift | unsigned_right_shift | '=='  | '!='  | '>'   | '<'   | '>='  | '<='
    ;

Operatori binari

La firma di un operatore >>> è soggetta alle stesse regole riportate nella sezione §15.10.3 per la firma di un operatore >>.

Il nome del metadato

La sezione "I.10.3.2 Operatori binari" di ECMA-335 ha già riservato il nome per un operatore di spostamento a destra senza segno - op_UnsignedRightShift.

Alberi delle espressioni LINQ

L'operatore >>> non sarà supportato in Alberi delle espressioni Linq perché la semantica degli operatori di >>> predefiniti sui tipi firmati non può essere rappresentata con precisione senza aggiungere conversioni a un tipo senza segno e indietro. Per altre informazioni, vedere https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-02-09.md#unsigned-right-shift-operator.

Collegamento dinamico

L'associazione dinamica usa i valori dell'enumerazione System.Linq.Expressions.ExpressionType per comunicare il tipo di operatore binario al gestore di runtime. Poiché non abbiamo un membro che rappresenta specificamente un operatore di spostamento a destra senza segno, l'associazione dinamica per l'operatore >>> non sarà supportata e la sezione sull'associazione statica e dinamica (§12.3) verrà modificata per riflettere questo aspetto.

Svantaggi

Alternative

Alberi delle espressioni LINQ

L'operatore >>> sarà supportato in Linq Expression Trees.

  • Per un operatore definito dall'utente, verrà creato un nodo BinaryExpression che punta al metodo dell'operatore.
  • Per gli operatori predefiniti
    • quando il primo operando è un tipo firmato, verrà creato un nodo BinaryExpression.
    • quando il primo operando è un tipo con segno, verrà aggiunta una conversione per il primo operando in un tipo senza segno, verrà creato un nodo BinaryExpression e verrà aggiunta la conversione del risultato a un tipo con segno.

Per esempio:

Expression<System.Func<int, int, int>> z = (x, y) => x >>> y; // (x, y) => Convert((Convert(x, UInt32) >> y), Int32)

Resolution:

Rifiutata, vedere https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-02-09.md#unsigned-right-shift-operator per altre informazioni.

Domande non risolte

Riunioni di design

https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-02-09.md