Sdílet prostřednictvím


Operátor posunu doprava bez znaménka

Poznámka

Tento článek je specifikace funkce. Specifikace slouží jako návrhový dokument pro funkci. Zahrnuje navrhované změny specifikace spolu s informacemi potřebnými při návrhu a vývoji funkce. Tyto články se publikují, dokud nebudou navrhované změny specifikace finalizovány a začleněny do aktuální specifikace ECMA.

Mezi specifikací funkce a dokončenou implementací může docházet k nějakým nesrovnalostem. Tyto rozdíly jsou zachyceny v příslušných poznámkách schůzky návrhu jazyka (LDM).

Další informace o procesu přijetí specifikací funkcí do jazyka C# najdete v článku o specifikacích .

Shrnutí

Operátor posunu vpravo bez znaménka bude C# podporován jako zabudovaný operátor (pro základní celočíselné typy) a jako uživatelsky definovaný operátor.

Motivace

Při práci s podepsanou celočíselnou hodnotou není neobvyklé, že budete potřebovat posunout bity doprava, aniž byste při každém posunu replikovali nejvyšší bit. I když toho lze dosáhnout u primitivních celočíselných typů pomocí běžného operátoru posunu, je před operací posunu a po ní nutné přetypování na nepodepsaný typ a zpět. V kontextu obecných matematických rozhraní, která knihovny hodlají zpřístupnit, může být potenciálně problematičtější, že typ nemusí mít nutně definovaný nebo známý předem ekvivalent bez znaménka, ale algoritmus může spoléhat na schopnost provádět operaci posunu doprava bez znaménka.

Podrobný návrh

Operátory a interpunkční znaky

Oddíl §6.4.6 bude upraven tak, aby zahrnoval operátor >>> - operátor posunu doprava bez znaménka:

unsigned_right_shift
    : '>>>'
    ;

unsigned_right_shift_assignment
    : '>>>='
    ;

Mezi tokeny v produkcích unsigned_right_shift a unsigned_right_shift_assignment nejsou povoleny žádné znaky jakéhokoli druhu, včetně mezer. Tyto výroby jsou zpracovávány speciálně, aby bylo možné správně zpracovávat type_parameter_lists.

Operátory posunu

Oddíl §12.11 se upraví tak, aby zahrnoval operátor >>> - operátor posunu doprava bez znaménka:

Operátory <<, >> a >>> slouží k provádění operací posunu bitů.

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

Pro operaci formuláře x << count nebo x >> count nebo x >>> count, rozlišení přetížení binárního operátoru (§12.4.5) se použije k výběru konkrétní implementace operátoru. Operandy jsou převedeny na typy parametrů vybraného operátoru a typ výsledku je návratový typ operátoru.

Předdefinované operátory posunu bez znaménka budou podporovat stejnou sadu podpisů, které v aktuální implementaci podporují předdefinované operátory posunu se znaménky.

  • Posunout doprava:

    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);
    

    Operátor >>> posune x doprava o počet bitů vypočítaný podle níže uvedeného popisu.

    Bity x s nízkým pořadím se zahodí, zbývající bity se posunou doprava a pozice prázdných bitů s vysokým pořadím se nastaví na nulu.

U předdefinovaných operátorů se počet bitů, které se mají posunout, vypočítá takto:

  • Pokud je typ xint nebo uint, počet posunů je určen nižšími pěti bity count. Jinými slovy, počet směn se vypočítá z count & 0x1F.
  • Pokud je typ xlong nebo ulong, počet posunů je dán šesti nejnižšími bity count. Jinými slovy, počet směn se vypočítá z count & 0x3F.

Pokud je výsledný počet směn nula, operátory směn jednoduše vrátí hodnotu x.

Posunovací operace nikdy nezpůsobí přetečení a produkují stejné výsledky v checked a unchecked kontekstech.

Operátory přiřazení

Oddíl §12.21 bude upraven tak, aby zahrnoval unsigned_right_shift_assignment následujícím způsobem:

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

Celočíselné typy

Oddíl integrálních typů §8.3.6 se upraví, aby zahrnoval informace o operátoru >>>. Příslušná odrážka je následující:

  • Pro binární <<, >> a >>> operátory je levý operand převeden na typ T, kde T je první z int, uint, longa ulong, které mohou plně představovat všechny možné hodnoty operandu. Operace se pak provádí pomocí přesnosti typu Ta typ výsledku je T.

Konstantní výrazy

Operátor >>> bude přidán do sady konstruktorů povolených v konstantních výrazech v §12.23.

Přetížení operátoru

Operátor >>> bude přidán do sady přetížitelných binárních operátorů v §12.4.3.

Povýšené operátory

Operátor >>> bude přidán do sady binárních operátorů, které umožňují zvednutí formuláře v §12.4.8.

Priorita operátorů a asociativita

Oddíl §12.4.2 se upraví tak, aby do kategorie Shift přidal operátor >>> a operátor >>>= do kategorie Přiřazení a výraz lambda.

Gramatické nejednoznačnosti

Operátor >>> podléhá stejným gramatickým nejednoznačnostem popsaným v §6.2.5 jako běžný operátor >>.

Operátoři

Oddíl §15.10 se upraví tak, aby zahrnoval operátor >>>.

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

Binární operátory

Podpis operátora >>> podléhá stejným pravidlům jako v §15.10.3 pro podpis operátora >>.

Název metadat

Oddíl I.10.3.2 Binární operátory ECMA-335 již rezervoval název operátoru posunu doprava bez znaménka – op_UnsignedRightShift.

Linq stromy výrazů

Operátor >>> nebude podporován v stromech výrazů Linq, protože sémantika předdefinovaných operátorů >>> u podepsaných typů nemůže být přesně reprezentována bez přidání převodů na nepodepsaný typ a zpět. Další informace najdete v tématu https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-02-09.md#unsigned-right-shift-operator.

Dynamická vazba

Vypadá to, že dynamické vazby používají hodnoty System.Linq.Expressions.ExpressionType výčtu ke komunikaci typu binárního operátoru s pořadačem modulu runtime. Vzhledem k tomu, že nemáme člena, který specificky reprezentuje operátor posunu doprava bez znaménka, dynamická vazba pro operátor >>> nebude podporována a oddíl o statické a dynamické vazbě (§12.3) bude upraven tak, aby tuto skutečnost zohlednil.

Nevýhody

Alternativy

Linq stromy výrazů

Operátor >>> bude podporován v LINQ Expression Trees.

  • U uživatelem definovaného operátoru se vytvoří uzel BinaryExpression odkazující na metodu operátoru.
  • Pro předdefinované operátory
    • Pokud je prvním operandem přiřazený typ, vytvoří se uzel BinaryExpression.
    • když je prvním operandem podepsaný typ, přidá se převod prvního operandu na nepodepsaný typ, vytvoří se uzel BinaryExpression a převod výsledku zpět na podepsaný typ se přidá.

Například:

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

Resolution:

Zamítnuto, další informace najdete v tématu https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-02-09.md#unsigned-right-shift-operator.

Nevyřešené otázky

Schůzky o designu

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