Partager via


IntPtr numérique

Remarque

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

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

Vous pouvez en savoir plus sur le processus d’adoption des speclets de fonctionnalités dans la norme de langage C# dans l’article sur les spécifications .

Résumé

Il s’agit d’une révision sur la fonctionnalité initiale d’entiers natifs (spécification), où les types nint/nuint étaient distincts des types sous-jacents System.IntPtr/System.UIntPtr. En bref, nous traitons maintenant nint/nuint en tant qu’alias de types simples System.IntPtr/System.UIntPtr, comme nous le faisons pour int par rapport à System.Int32. L’indicateur de fonctionnalité System.Runtime.CompilerServices.RuntimeFeature.NumericIntPtr runtime déclenche ce nouveau comportement.

Création

8.3.5 Types simples

C# fournit un ensemble de types struct prédéfinis appelés types simples. Les types simples sont identifiés par le biais de mots clés, mais ces mots clés sont simplement des alias pour les types de struct prédéfinis dans l’espace de noms System, comme décrit dans le tableau ci-dessous.

Mot-clé Type aliasé
sbyte System.SByte
byte System.Byte
short System.Int16
ushort System.UInt16
int System.Int32
uint System.UInt32
nint System.IntPtr
nuint System.UIntPtr
long System.Int64
ulong System.UInt64
char System.Char
float System.Single
double System.Double
bool System.Boolean
decimal System.Decimal

[...]

8.3.6 Types intégraux

C# prend en charge onze types entiers : sbyte, byte, short, ushort, int, uint, nint, nuint, long, ulong, et char. [...]

8.8 Types non managés

En d’autres termes, une unmanaged_type est l’une des suivantes :

  • sbyte, byte, short, ushort, int, uint, nint, nuint, long, ulong, char, float, double, decimalou bool.
  • Tout enum_type.
  • Tout struct_type défini par l’utilisateur qui n’est pas un type construit et ne contient que des champs de unmanaged_type.
  • Dans un code non sécurisé, tout pointer_type.

10.2.3 Conversions numériques implicites

Les conversions numériques implicites sont les suivantes :

  • De sbyte à short, int, nint, long, float, doubleou decimal.
  • De byte à short, ushort, int, uint, nint, nuint, long, ulong, float, doubleou decimal.
  • De short à int, nint, long, float, doubleou decimal.
  • De ushort à int, uint, nint, nuint, long, ulong, float, doubleou decimal.
  • De int à nint, long, float, doubleou decimal.
  • De uint à nuint, long, ulong, float, doubleou decimal.
  • De nint à long, float, doubleou decimal.
  • De nuint à ulong, float, doubleou decimal.
  • De long à float, doubleou decimal.
  • De ulong à float, doubleou decimal.
  • De char à ushort, int, uint, nint, nuint, long, ulong, float, doubleou decimal.
  • De float à double.

[...]

10.2.11 Conversions d’expressions constantes implicites

Une conversion d’expression constante implicite permet les conversions suivantes :

  • Une constant_expression de type int peut être convertie en type sbyte, byte, short, ushort, uint, nint, nuintou ulong, à condition que la valeur du constant_expression se trouve dans la plage du type de destination. [...]

10.3.2 Conversions numériques explicites

Les conversions numériques explicites sont les conversions d’un numeric_type vers une autre numeric_type pour laquelle une conversion numérique implicite n’existe pas déjà :

  • De sbyte à byte, ushort, uint, nuint, ulongou char.
  • De byte à sbyte ou char.
  • De short à sbyte, byte, ushort, uint, nuint, ulongou char.
  • De ushort à sbyte, byte, shortou char.
  • De int à sbyte, byte, short, ushort, uint, nuint, ulongou char.
  • De uint à sbyte, byte, short, ushort, int, nintou char.
  • De long à sbyte, byte, short, ushort, int, uint, nint, nuint, ulongou char.
  • De nint à sbyte, byte, short, ushort, int, uint, nuint, ulongou char.
  • De nuint à sbyte, byte, short, ushort, int, uint, nint, longou char.
  • De ulong à sbyte, byte, short, ushort, int, uint, nint, nuint, longou char.
  • De char à sbyte, byteou short.
  • De float à sbyte, byte, short, ushort, int, uint, nint, nuint, long, ulong, charou decimal.
  • De double à sbyte, byte, short, ushort, int, uint, nint, nuint, long, ulong, char, floatou decimal.
  • De decimal à sbyte, byte, short, ushort, int, uint, nint, nuint, long, ulong, char, floatou double.

[...]

10.3.3 Conversions d’énumération explicites

Les conversions d’énumération explicites sont les suivantes :

  • À partir de sbyte, byte, short, ushort, int, uint, nint, nuint, long, ulong, char, float, doubleou decimal à n’importe quel enum_type.
  • De n’importe quel enum_type à sbyte, byte, short, ushort, int, uint, nint, nuint, long, ulong, char, float, doubleou decimal.
  • De tout enum_type à tout autre enum_type.

12.6.4.7 Meilleure cible de conversion

Étant donné deux types T₁ et T₂, T₁ est une meilleure cible de conversion que T₂ si l'un des critères suivants est rempli :

  • Une conversion implicite de T₁ en T₂ existe et aucune conversion implicite de T₂ en T₁ existe
  • T₁ est Task<S₁>, T₂ est Task<S₂>et S₁ est une meilleure cible de conversion que S₂
  • T₁ est S₁ ou S₁?S₁ est un type intégral signé et T₂ est S₂ ou S₂?S₂ est un type intégral non signé. Plus précisément : [...]

Accès aux éléments 12.8.12

[...] Le nombre d’expressions dans la argument_list doit être identique au rang du array_type, et chaque expression doit être de type int, uint, nint, nuint, long, ou ulong, ou doit être implicitement convertible en un ou plusieurs de ces types.

11.8.12.2 Accès au tableau

[...] Le nombre d’expressions dans la argument_list doit être identique au rang du array_type, et chaque expression doit être de type int, uint, nint, nuint, long, ou ulong, ou doit être implicitement convertible en un ou plusieurs de ces types.

[...] Le traitement à l’exécution d’un accès à un tableau de la forme P[A], où P est une primary_no_array_creation_expression d’un array_type et A est une argument_list, consiste en les étapes suivantes : [...]

  • Les expressions d’index de la argument_list sont évaluées dans l’ordre, de gauche à droite. Après l'évaluation de chaque expression d'index, une conversion implicite vers l'un des types suivants est effectuée : int, uint, nint, nuint, long, ulong. Le premier type de cette liste pour lequel une conversion implicite existe est choisi. [...]

12.8.16 Opérateurs suffixés d’incrémentation et de décrémentation

La résolution de surcharge d’opérateur unaire est appliquée pour sélectionner une implémentation d’opérateur spécifique. Les opérateurs ++ et -- prédéfinis existent pour les types suivants : sbyte, byte, short, ushort, int, uint, nint, nuint,long, ulong, char, float, double, decimalet tout type d’énumération.

12.9.2 Opérateur unaire plus

Les opérateurs plus unaires prédéfinis sont les suivants :

...
nint operator +(nint x);
nuint operator +(nuint x);

12.9.3 Opérateur unaire moins

Les opérateurs moins unaires prédéfinis sont les suivants :

  • Négation entière :

    ...
    nint operator –(nint x);
    

12.8.16 Opérateurs suffixés d’incrémentation et de décrémentation

Les opérateurs ++ et -- prédéfinis existent pour les types suivants : sbyte, byte, short, ushort, int, uint, nint, nuint, long, ulong, char, float, double, decimalet tout type d’énumération.

11.7.19 Expressions de valeur par défaut

En outre, un default_value_expression est une expression constante si le type est l’un des types valeur suivants : sbyte, byte, short, ushort, int, uint, nint, nuint, long, ulong, char, float, double, decimal, bool, ou tout type d’énumération.

12.9.5 Opérateur complément binaire

Les opérateurs de complément au niveau du bit prédéfinis sont les suivants :

...
nint operator ~(nint x);
nuint operator ~(nuint x);

12.9.6 Opérateurs d’incrémentation et de décrémentation de préfixe

Les opérateurs ++ et -- prédéfinis existent pour les types suivants : sbyte, byte, short, ushort, int, uint, nint, nuint, long, ulong, char, float, double, decimalet tout type d’énumération.

12.10 Opérateurs arithmétiques

12.10.2 Opérateur de multiplication

Les opérateurs de multiplication prédéfinis sont répertoriés ci-dessous. Les opérateurs calculent tous le produit de x et de y.

  • Multiplication des entiers :

    ...
    nint operator *(nint x, nint y);
    nuint operator *(nuint x, nuint y);
    

12.10.3 Opérateur de division

Les opérateurs de division prédéfinis sont répertoriés ci-dessous. Les opérateurs calculent tous le quotient de x et de y.

  • Division entière :

    ...
    nint operator /(nint x, nint y);
    nuint operator /(nuint x, nuint y);
    

12.10.4 Opérateur de reste

Les opérateurs de reste prédéfinis sont listés ci-dessous. Les opérateurs calculent tous le reste de la division entre x et y.

  • Reste entier :

    ...
    nint operator %(nint x, nint y);
    nuint operator %(nuint x, nuint y);
    

12.10.5 Opérateur d’addition

  • Ajout entier :

    ...
    nint operator +(nint x, nint y);
    nuint operator +(nuint x, nuint y);
    

12.10.6 Opérateur de soustraction

  • Soustraction entière :

    ...
    nint operator –(nint x, nint y);
    nuint operator –(nuint x, nuint y);
    

12.11 Opérateurs de décalage

Les opérateurs de décalage prédéfinis sont listés ci-dessous.

  • Décalage vers la gauche :

    ...
    nint operator <<(nint x, int count);
    nuint operator <<(nuint x, int count);
    
  • Décalage vers la droite :

    ...
    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.

    Lorsque x est de type int, nint ou long, les bits de bas 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 si x est non négatif et défini sur un si x est négatif.

    Lorsque x est de type uint, nuint ou ulong, les bits de bas 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.

  • Décalage logique à droite :

    ...
    nint operator >>>(nint x, int count);
    nuint operator >>>(nuint x, int count);
    

Pour les opérateurs prédéfinis, le nombre de bits à déplacer est calculé comme suit : [...]

  • Lorsque le type de x est nint ou nuint, le nombre de décalages est donné par les cinq bits de count de faible ordre sur une plateforme 32 bits, ou les six bits de count de l’ordre inférieur sur une plateforme 64 bits.

12.12 Opérateurs relationnels et de test de type

12.12.2 Opérateurs de comparaison d’entiers

Les opérateurs de comparaison d’entiers prédéfinis sont les suivants :

...
bool operator ==(nint x, nint y);
bool operator ==(nuint x, nuint y);

bool operator !=(nint x, nint y);
bool operator !=(nuint x, nuint y);

bool operator <(nint x, nint y);
bool operator <(nuint x, nuint y);

bool operator >(nint x, nint y);
bool operator >(nuint x, nuint y);

bool operator <=(nint x, nint y);
bool operator <=(nuint x, nuint y);

bool operator >=(nint x, nint y);
bool operator >=(nuint x, nuint y);

12.12 Opérateurs logiques

12.12.2 Opérateurs logiques entiers

Les opérateurs logiques entiers prédéfinis sont les suivants :

...
nint operator &(nint x, nint y);
nuint operator &(nuint x, nuint y);

nint operator |(nint x, nint y);
nuint operator |(nuint x, nuint y);

nint operator ^(nint x, nint y);
nuint operator ^(nuint x, nuint y);

Expressions constantes 12.22

Une expression constante peut être un type valeur ou un type référence. Si une expression constante est un type valeur, il doit s’agir de l’un des types suivants : sbyte, byte, short, ushort, int, uint, nint, nuint, long, ulong, char, float, double, decimal, bool, ou tout type d’énumération.

[...]

Une conversion d’expression constante implicite permet à une expression constante de type int d’être convertie en sbyte, byte, short, ushort, uint, nint, nuint, ou ulong, à condition que la valeur de l’expression constante se trouve dans la plage du type de destination.

Accès aux éléments de tableau 17.4

Les éléments de tableau sont accessibles à l’aide d’expressions element_access du formulaire A[I₁, I₂, ..., Iₓ], où A est une expression d’un type de tableau et chaque Iₑ est une expression de type int, uint, nint, nuint,long, ulong, ou peut être convertie implicitement en un ou plusieurs de ces types. Le résultat d’un accès à un élément de tableau est une variable, à savoir l’élément de tableau sélectionné par les index.

23.5 Conversions de pointeur

23.5.1 Général

[...]

En outre, dans un contexte non sécurisé, l’ensemble de conversions explicites disponibles est étendu pour inclure les conversions de pointeur explicite suivantes :

  • De tout pointer_type à tout autre pointer_type.
  • De sbyte, byte, short, ushort, int, uint, nint, nuint,longou ulong à n’importe quel pointer_type.
  • De n’importe quel pointer_type à sbyte, byte, short, ushort, int, uint, nint, nuint,longou ulong.

23.6.4 Accès à l’élément pointeur

[...] Dans un accès d’élément de pointeur du formulaire P[E], P doit être une expression d’un type de pointeur autre que void*, et E doit être une expression qui peut être implicitement convertie en int, uint, nint, nuint,longou ulong.

23.6.7 Arithmétique des pointeurs

Dans un contexte non sécurisé, l’opérateur + et l’opérateur peuvent être appliqués aux valeurs de tous les types de pointeurs, sauf void*. Ainsi, pour chaque type de pointeur T*, les opérateurs suivants sont implicitement définis :

[...]
T* operator +(T* x, nint y);
T* operator +(T* x, nuint y);
T* operator +(nint x, T* y);
T* operator +(nuint x, T* y);
T* operator -(T* x, nint y);
T* operator -(T* x, nuint y);

Étant donné une expression P d’un type pointeur T* et une expression N de type int, uint, nint, nuint,longou ulong, les expressions P + N et N + P calculent la valeur de pointeur de type T* qui résulte de l’ajout de N * sizeof(T) à l’adresse donnée par P. De même, l’expression P – N calcule la valeur du pointeur de type T* qui résulte de la soustraction des N * sizeof(T) de l’adresse donnée par P.

Différentes considérations

Changements cassants

L'un des principaux impacts de cette conception est que System.IntPtr et System.UIntPtr gagnent des opérateurs intégrés (conversions, unaires et binaires).
Ceux-ci incluent les opérateurs checked, ce qui signifie que les opérateurs suivants sur ces types lanceront désormais une exception en cas de dépassement :

  • IntPtr + int
  • IntPtr - int
  • IntPtr -> int
  • long -> IntPtr
  • void* -> IntPtr

Encodage des métadonnées

Cette conception signifie que nint et nuint peuvent simplement être émis en tant que System.IntPtr et System.UIntPtr, sans utiliser System.Runtime.CompilerServices.NativeIntegerAttribute.
De même, lors du chargement des métadonnées, NativeIntegerAttribute peut être ignoré.