Partager via


Opérateur de décalage vers la droite non signé

Remarque

Cet article est une spécification de fonctionnalité. La spécification sert de document de conception pour la fonctionnalité. Elle inclut les changements de spécification proposés, ainsi que les informations nécessaires à la conception et au développement de la fonctionnalité. Ces articles sont publiés jusqu'à ce que les changements proposés soient finalisés et incorporés dans la spécification ECMA actuelle.

Il peut y avoir des différences entre la spécification de la fonctionnalité et l'implémentation réalisée. Ces différences sont consignées dans les notes pertinentes de la réunion de conception linguistique (LDM).

Pour en savoir plus sur le processus d'adoption des speclets de fonctionnalité dans la norme du langage C#, consultez l'article sur les spécifications.

Problème de champion : https://github.com/dotnet/csharplang/issues/4682

Récapitulatif

C# prendra en charge un opérateur de décalage à droite non signé en tant qu’opérateur natif (pour les types intégraux primitifs) et en tant qu’opérateur défini par l’utilisateur.

Motivation

Lorsque l'on travaille avec une valeur intégrale signée, il n'est pas rare que l'on doive décaler des bits vers la droite sans reproduire le bit de poids fort à chaque décalage. Bien que cela puisse être obtenu pour les types intégraux primitifs avec un opérateur de décalage standard, il est nécessaire de faire une conversion en un type non signé avant l’opération de décalage et une conversion inverse après. Dans le contexte des interfaces mathématiques génériques que les bibliothèques prévoient d'exposer, cela est potentiellement plus problématique car le type peut ne pas avoir une contrepartie non signée définie ou connue d'emblée par le code mathématique générique, alors qu'un algorithme peut s'appuyer sur la capacité à effectuer une opération de décalage vers la droite non signée.

Conception détaillée

Opérateurs et signes de ponctuation

La section 6.4.6 sera modifiée pour inclure l'opérateur >>> - l'opérateur de décalage à droite non signé :

unsigned_right_shift
    : '>>>'
    ;

unsigned_right_shift_assignment
    : '>>>='
    ;

Aucun caractère d'aucune sorte (pas même les espaces blancs) n'est autorisé entre les jetons des productions unsigned_right_shift et unsigned_right_shift_assignment. Ces productions font l'objet d'un traitement spécial afin de permettre la gestion correcte des listes de type_parameter_lists

Opérateurs de décalage

La section 12.11 sera modifiée pour inclure l'opérateur >>> - l'opérateur de décalage à droite non signé :

Les opérateurs <<, >> et >>> sont utilisés pour réaliser des opérations de décalage de bits.

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

Pour une opération de la forme x << count, x >> count ou x >>> count la résolution de surcharge de l’opérateur binaire (§12.4.5) est appliquée pour sélectionner une implémentation spécifique de l’opérateur. Les opérandes sont convertis en types de paramètre de l’opérateur sélectionné, et le type du résultat correspond au type de retour de l’opérateur.

Les opérateurs de décalage non signés prédéfinis prendront en charge le même ensemble de signatures que les opérateurs de décalage signés prédéfinis dans l'implémentation actuelle.

  • Décalage vers la droite :

    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’opérateur >>> déplace x vers la droite d’un nombre de bits calculé comme décrit ci-dessous.

    Les bits de faible ordre de x sont ignorés, les bits restants sont décalés vers la droite et les positions de bits vides de l’ordre élevé sont définies sur zéro.

Pour les opérateurs prédéfinis, le nombre de bits à décaler est calculé comme suit:

  • Lorsque le type de x est int ou uint, le nombre de décalages est donné par les cinq bits de bas ordre de count. En d'autres termes, le nombre de décalages est calculé à partir de count & 0x1F.
  • Lorsque le type de x est long ou ulong, le nombre de décalages est donné par les six bits de poids faible de count. En d'autres termes, le nombre de décalages est calculé à partir de count & 0x3F.

Si le nombre de décalages résultant est nul, les opérateurs de décalage renvoient simplement la valeur de x.

Les opérations de décalage ne provoquent jamais de dépassements de capacité et donnent les mêmes résultats dans des contextes checked et unchecked.

Opérateurs d’assignation

La section 12.21 sera modifiée pour inclure unsigned_right_shift_assignment comme suit :

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

Types intégraux

Les types intégraux de la section §8.3.6 seront ajustés pour inclure des informations sur l’opérateur >>>. Le point pertinent est le suivant :

  • Pour les opérateurs binaires <<, >> et >>>, l’opérande gauche est converti en type T, où T est le premier de int, uint, long et ulong, qui peuvent représenter entièrement toutes les valeurs possibles de l’opérande. L’opération est ensuite effectuée à l’aide de la précision du type T, et le type du résultat est T.

Expressions de constantes

L’opérateur >>> sera ajouté à l’ensemble de constructions autorisées dans les expressions constantes au §12.23.

Surcharge d’opérateur

L’opérateur >>> sera ajouté à l’ensemble d’opérateurs binaires surchargeables au §12.4.3.

Opérateurs levés

L’opérateur >>> sera ajouté à l’ensemble d’opérateurs binaires autorisant une forme élevée au §12.4.8.

Priorité des opérateurs et associativité

La section §12.4.2 sera ajustée pour ajouter les opérateurs >>> à la catégorie « Shift » et >>>= à la catégorie « Affectation et l'expression lambda ».

Ambiguïtés grammaticales

L’opérateur >>> est soumis aux mêmes ambiguïtés grammaticales décrites au §6.2.5 comme opérateur de >> standard.

Opérateurs

La section §15.10 sera ajustée pour inclure l'opérateur >>>.

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

Opérateurs binaires

La signature d’un opérateur >>> est soumise aux mêmes règles qu’au §15.10.3 pour la signature d’un opérateur >>.

Nom des métadonnées

La section « I.10.3.2 Binary operators » de l'ECMA-335 a déjà réservé le nom d'un opérateur de décalage à droite non signé - op_UnsignedRightShift.

Arbres d'expression Linq

L'opérateur >>> ne sera pas pris en charge dans les arbres d'expressions LINQ, car la sémantique des opérateurs >>> prédéfinis sur les types signés ne peut pas être représentée avec précision sans ajouter de conversions à un type non signé et inversement. Consultez la rubrique https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-02-09.md#unsigned-right-shift-operator (éventuellement en anglais) pour plus d'informations.

Liaison dynamique

Il semble que la liaison dynamique utilise les valeurs de l'enum System.Linq.Expressions.ExpressionType pour communiquer le type d'opérateur binaire à la liaison d'exécution. Comme nous n'avons pas de membre représentant spécifiquement l'opérateur unsigned right shift, la liaison dynamique pour l'opérateur >>> ne sera pas supportée et la section sur la liaison statique et dynamique (12.3) sera ajustée pour refléter cela.

Inconvénients

Alternatives

Arbres d'expression Linq

L'opérateur >>> sera pris en charge dans les arbres d'expression Linq.

  • Pour un opérateur défini par l’utilisateur, un nœud BinaryExpression pointant vers la méthode d’opérateur est créé.
  • Pour les opérateurs prédéfinis
    • lorsque le premier opérande est un type non signé, un nœud BinaryExpression est créé.
    • lorsque le premier opérande est un type signé, une conversion du premier opérande en type non signé est ajoutée, un nœud BinaryExpression est créé et la conversion du résultat vers le type signé est ajoutée.

Exemple :

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

Resolution:

En cas de rejet, consultez la rubrique https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-02-09.md#unsigned-right-shift-operator pour plus d'informations.

Questions non résolues

Réunions de conception

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