Right-Shift-Operator ohne Vorzeichen
Anmerkung
Dieser Artikel ist eine Featurespezifikation. Die Spezifikation dient als Designdokument für das Feature. Es enthält vorgeschlagene Spezifikationsänderungen sowie Informationen, die während des Entwurfs und der Entwicklung des Features erforderlich sind. Diese Artikel werden veröffentlicht, bis die vorgeschlagenen Spezifikationsänderungen abgeschlossen und in die aktuelle ECMA-Spezifikation aufgenommen werden.
Es kann einige Abweichungen zwischen der Featurespezifikation und der abgeschlossenen Implementierung geben. Diese Unterschiede sind in den entsprechenden Hinweisen zum Language Design Meeting (LDM) festgehalten.
Mehr über den Prozess der Adaption von Funktionen in den C#-Sprachstandard erfahren Sie in dem Artikel über die Spezifikationen.
Zusammenfassung
Ein vorzeichenloser Right-Shift-Operator wird von C# als integrierter Operator (für primitive Integraltypen) und als benutzerdefinierter Operator unterstützt.
Motivation
Bei der Arbeit mit vorzeichenbehafteten Integralwerten ist es nicht ungewöhnlich, dass Sie Bits nach rechts verschieben müssen, ohne das Bit hoher Ordnung bei jeder Verschiebung zu replizieren. Während dies bei primitiven Integraltypen mit einem regulären Verschiebeoperator erreicht werden kann, ist vor dem Verschiebevorgang ein Cast in einen vorzeichenlosen Typ und danach ein Cast zurück erforderlich. Im Zusammenhang mit den generischen mathematischen Schnittstellen, die die Bibliotheken planen, ist dies potenziell problematischer, da der Typ nicht unbedingt ein vorzeichenloses Gegenstück haben muss, das definiert oder dem generischen mathematischen Code im Voraus bekannt ist, ein Algorithmus jedoch auf die Fähigkeit angewiesen sein könnte, einen vorzeichenlosen Right-Shift-Operator durchzuführen.
Detailliertes Design
Operatoren und Trennzeichen
Abschnitt §6.4.6 wird angepasst, um den >>>
-Operator aufzunehmen – den Right-Shift-Operator ohne Vorzeichen:
unsigned_right_shift
: '>>>'
;
unsigned_right_shift_assignment
: '>>>='
;
Zwischen den Token in den Produktionen unsigned_right_shift und unsigned_right_shift_assignment sind keinerlei Zeichen (auch keine Leerzeichen) zugelassen. Diese Produktionen werden speziell behandelt, um die korrekte Behandlung von typ_parameter_lists zu ermöglichen.
Schiebeoperatoren
Abschnitt §12.11 wird angepasst, um den >>>
-Operator – den Right-Shift-Operator ohne Vorzeichen – aufzunehmen:
Die Operatoren <<
, >>
und >>>
werden zum Ausführen von Bitverschiebungsvorgängen verwendet.
shift_expression
: additive_expression
| shift_expression '<<' additive_expression
| shift_expression right_shift additive_expression
| shift_expression unsigned_right_shift additive_expression
;
Für einen Vorgang der Form x << count
oder x >> count
oder x >>> count
wird die Überladungsauflösung für binäre Operatoren (§12.4.5) angewendet, um eine bestimmte Implementierung des Operators auszuwählen. Die Operanden werden in die Parametertypen des ausgewählten Operators konvertiert, und der Typ des Ergebnisses ist der Rückgabetyp des Operators.
Die vordefinierten vorzeichenlosen Verschiebungsoperatoren unterstützen dieselbe Reihe von Signaturen, die vordefinierte vorzeichenbehaftete Verschiebungsoperatoren in der aktuellen Implementierung unterstützen.
Nach rechts verschieben:
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);
Der
>>>
-Operator verschiebtx
um eine Anzahl von Bits nach rechts, die wie unten beschrieben berechnet wird.Die niederwertigen Bits von
x
werden verworfen, die verbleibenden Bits werden nach rechts verschoben und die höherwertigen leeren Bitpositionen werden auf Null festgelegt.
Für die vordefinierten Operatoren wird die Anzahl der zu verschiebenden Bits wie folgt berechnet:
- Wenn der Typ von
x
int
oderuint
ist, wird die Anzahl der Verschiebungen durch die niederwertigen fünf Bits voncount
bestimmt. Mit anderen Worten, die Anzahl der Verschiebungen wird auscount & 0x1F
berechnet. - Wenn der Typ von
x
long
oderulong
ist, wird die Anzahl der Verschiebungen durch die niederwertigen sechs Bits voncount
bestimmt. Mit anderen Worten, die Anzahl der Verschiebungen wird auscount & 0x3F
berechnet.
Wenn die resultierende Schichtanzahl null ist, geben die Schichtoperatoren einfach den Wert von x
zurück.
Verschiebungsvorgänge führen nie zu Überläufen und liefern in checked
- und unchecked
-Kontexten die gleichen Ergebnisse.
Assignment operators (Zuweisungsoperatoren)
Abschnitt §12.21 wird angepasst, um unsigned_right_shift_assignment wie folgt aufzunehmen:
assignment_operator
: '='
| '+='
| '-='
| '*='
| '/='
| '%='
| '&='
| '|='
| '^='
| '<<='
| right_shift_assignment
| unsigned_right_shift_assignment
;
Ganzzahlige Typen
Der Abschnitt Integraltypen §8.3.6 wird angepasst, um Informationen über den Operator >>>
aufzunehmen. Der entsprechende Punkt lautet wie folgt:
- Für die binären
<<
,>>
und>>>
Operatoren wird der linke Operand in TypT
konvertiert, wobeiT
der erste vonint
,uint
,long
undulong
ist, der alle möglichen Werte des Operanden vollständig darstellen kann. Der Vorgang wird dann mit der Genauigkeit des TypsT
durchgeführt, und der Typ des Ergebnisses istT
.
Konstante Ausdrücke
Der Operator >>>
wird der Menge der in konstanten Ausdrücken zulässigen Konstrukte unter §12.23 hinzugefügt.
Überladen von Operatoren
Der Operator >>>
wird in die Menge der überladbaren binären Operatoren unter §12.4.3 aufgenommen.
„Lifted“ Operatoren
Der Operator >>>
wird in die Menge der binären Operatoren aufgenommen, die in §12.4.8 eine gehobene Form zulassen.
Operatorrangfolge und Assoziativität
Abschnitt §12.4.2 wird angepasst, um den >>>
-Operator zur Kategorie "Verschiebung" und den >>>=
-Operator zur Kategorie "Zuweisung und Lambda-Ausdruck" hinzuzufügen.
Grammatikunklarheiten
Der >>>
-Operator unterliegt den gleichen grammatikalischen Zweideutigkeiten, die in §6.2.5 als regulärer >>
-Operator beschrieben sind.
Operatoren
Der Abschnitt §15.10 wird angepasst, um den >>>
-Operator aufzunehmen.
overloadable_binary_operator
: '+' | '-' | '*' | '/' | '%' | '&' | '|' | '^' | '<<'
| right_shift | unsigned_right_shift | '==' | '!=' | '>' | '<' | '>=' | '<='
;
Binäre Operatoren
Die Signatur eines >>>
-Operators unterliegt den gleichen Regeln wie bei §15.10.3 für die Signatur eines >>
-Operators.
Metadatenname
Abschnitt "I.10.3.2 Binäre Operatoren" der ECMA-335 hat bereits den Namen für einen Right-Shift-Operator ohne Vorzeichen reserviert – op_UnsignedRightShift.
Linq-Ausdrucksbäume
Der >>>
-Operator wird in Linq-Ausdrucksbäumen nicht unterstützt, da die Semantik der vordefinierten >>>
-Operatoren auf vorzeichenbehafteten Typen nicht korrekt dargestellt werden kann, ohne Konvertierungen in einen vorzeichenlosen Typ und zurück hinzuzufügen. Weitere Informationen finden Sie unter https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-02-09.md#unsigned-right-shift-operator.
Dynamische Bindung
Es sieht so aus, als ob die dynamische Bindung Werte des Enums System.Linq.Expressions.ExpressionType verwendet, um die Art des binären Operators an den Runtime Binder zu übermitteln. Da wir kein Mitglied haben, das speziell einen Right-Shift-Operator ohne Vorzeichen repräsentiert, wird die dynamische Bindung für den >>>
-Operator nicht unterstützt und der Abschnitt über statische und dynamische Bindung (§12.3) wird entsprechend angepasst.
Nachteile
Alternativen
Linq-Ausdrucksbäume
Der >>>
-Operator wird in Linq-Ausdrucksbäumen unterstützt.
- Für einen benutzerdefinierten Operator wird ein BinaryExpression-Knoten erstellt, der auf die Operatormethode zeigt.
- Für vordefinierte Operatoren
- Wenn der erste Operand ein Typ mit Vorzeichen ist, wird ein Knoten BinaryExpression erstellt.
- Wenn der erste Operand ein Typ mit Vorzeichen ist, wird eine Konvertierung für den ersten Operanden in einen Typ ohne Vorzeichen hinzugefügt, ein Knoten BinaryExpression erstellt und eine Konvertierung für das Ergebnis zurück in den Typ mit Vorzeichen hinzugefügt.
Zum Beispiel:
Expression<System.Func<int, int, int>> z = (x, y) => x >>> y; // (x, y) => Convert((Convert(x, UInt32) >> y), Int32)
Resolution:
Abgelehnt, siehe https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-02-09.md#unsigned-right-shift-operator für weitere Informationen.
Ungelöste Fragen
Design-Meetings
https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-02-09.md
C# feature specifications