Condividi tramite


IntPtr numerico

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.

Ulteriori informazioni sul processo di adozione degli speclet delle funzionalità nello standard del linguaggio C# sono disponibili nell'articolo sulle specifiche di .

Sommario

Si tratta di una revisione della funzionalità iniziale dei numeri interi nativi (specifica), in cui i tipi di nint/nuint erano distinti dai tipi sottostanti System.IntPtr/System.UIntPtr. In breve, ora trattiamo nint/nuint come semplici tipi alias di System.IntPtr/System.UIntPtr, come facciamo per int in relazione a System.Int32. Il flag di funzionalità di runtime System.Runtime.CompilerServices.RuntimeFeature.NumericIntPtr attiva questo nuovo comportamento.

Disegno

8.3.5 Tipi semplici

C# fornisce un set di tipi di struct predefiniti denominati tipi semplici. I tipi semplici vengono identificati tramite parole chiave, ma queste parole chiave sono semplicemente alias per i tipi di struct predefiniti nello spazio dei nomi System, come descritto nella tabella seguente.

parola-chiave tipo con 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 Tipi integrali

C# supporta undici tipi integrali: sbyte, byte, short, ushort, int, uint, nint, nuint, long, ulonge char. [...]

8.8 Tipi non gestiti

In altre parole, un unmanaged_type è uno dei seguenti:

  • sbyte, byte, short, ushort, int, uint, ,nint, nuint,, long, ulong, char, float, double, decimalo bool.
  • Qualsiasi enum_type.
  • Qualsiasi struct_type definita dall'utente che non è un tipo composto e contiene solo campi di unmanaged_type.
  • Nel codice non sicuro, qualsiasi pointer_type.

10.2.3 Conversioni numeriche implicite

Le conversioni numeriche implicite sono:

  • Da sbyte a short, int, nint, long, float, doubleo decimal.
  • Da byte a short, ushort, int, uint, nint, nuint, long, ulong, float, doubleo decimal.
  • Da short a int, nint, long, float, doubleo decimal.
  • Da ushort a int, uint, nint, nuint, long, ulong, float, doubleo decimal.
  • Da int a nint, long, float, doubleo decimal.
  • Da uint a nuint, long, ulong, float, doubleo decimal.
  • Da nint a long, float, doubleo decimal.
  • Da nuint a ulong, float, doubleo decimal.
  • Da long a float, doubleo decimal.
  • Da ulong a float, doubleo decimal.
  • Da char a ushort, int, uint, nint, nuint, long, ulong, float, doubleo decimal.
  • Da float a double.

[...]

10.2.11 Conversioni implicite di espressioni costanti

Una conversione implicita di espressioni costanti consente le conversioni seguenti:

  • Un constant_expression di tipo int può essere convertito nel tipo sbyte, byte, short, ushort, uint, nint, nuinto ulong, purché il valore del constant_expression sia compreso nell'intervallo del tipo di destinazione. [...]

10.3.2 Conversioni numeriche esplicite

Le conversioni numeriche esplicite sono le conversioni da un numeric_type a un'altra numeric_type per cui non esiste già una conversione numerica implicita:

  • Da sbyte a byte, ushort, uint, nuint, ulongo char.
  • Da byte a sbyte o char.
  • Da short a sbyte, byte, ushort, uint, nuint, ulongo char.
  • Da ushort a sbyte, byte, shorto char.
  • Da int a sbyte, byte, short, ushort, uint, nuint, ulongo char.
  • Da uint a sbyte, byte, short, ushort, int, ninto char.
  • Da long a sbyte, byte, short, ushort, int, uint, ,nint, nuint,, ulongo char.
  • Da nint a sbyte, byte, short, ushort, int, uint, nuint, ulongo char.
  • Da nuint a sbyte, byte, short, ushort, int, uint, nint, longo char.
  • Da ulong a sbyte, byte, short, ushort, int, uint, ,nint, nuint,, longo char.
  • Da char a sbyte, byteo short.
  • Da float a sbyte, byte, short, ushort, int, uint, nint, nuint, long, ulong, charo decimal.
  • Da double a sbyte, byte, short, ushort, int, uint, nint, nuint, long, ulong, char, floato decimal.
  • Da decimal a sbyte, byte, short, ushort, int, uint, nint, nuint, long, ulong, char, floato double.

[...]

10.3.3 Conversioni esplicite di enumerazione

Le conversioni esplicite di enumerazione sono:

  • Da sbyte, byte, short, ushort, int, uint, nint, nuint, long, ulong, char, float, doubleo decimal a qualsiasi enum_type.
  • Da qualsiasi enum_type a sbyte, byte, short, ushort, int, uint, nint, nuint, long, ulong, char, float, doubleo decimal.
  • Da qualunque enum_type a qualunque altro enum_type.

12.6.4.7 Destinazione di conversione migliore

Dato due tipi T₁ e T₂, T₁ è una destinazione di conversione migliore rispetto a T₂ se uno dei blocchi seguenti:

  • Esiste una conversione implicita da T₁ a T₂ e non esiste alcuna conversione implicita da T₂ a T₁
  • T₁ è Task<S₁>, T₂ è Task<S₂>e S₁ è una destinazione di conversione migliore rispetto a S₂
  • T₁ è S₁ o S₁? in cui S₁ è un tipo integrale con segno e T₂ è S₂ o S₂? dove S₂ è un tipo integrale senza segno. In particolare: [...]

12.8.12 Accesso all'elemento

[...] Il numero di espressioni nella argument_list deve essere uguale al rango del array_typee ogni espressione deve essere di tipo int, uint, nint, nuint, long, o ulong, o deve essere implicitamente convertibile in uno o più di questi tipi.

11.8.12.2 Accesso alla matrice

[...] Il numero di espressioni nella argument_list deve essere uguale al rango del array_typee ogni espressione deve essere di tipo int, uint, nint, nuint, long, o ulong, o deve essere implicitamente convertibile in uno o più di questi tipi.

[...] L'elaborazione in fase di esecuzione di un accesso di matrice alla forma P[A], dove P è un primary_no_array_creation_expression di un array_type e A è un argument_list, è costituita dai passaggi seguenti: [...]

  • Le espressioni di indice del argument_list vengono valutate in ordine, da sinistra a destra. Dopo la valutazione di ogni espressione di indice, viene eseguita una conversione implicita in uno dei tipi seguenti: int, uint, nint, nuint, long, ulong. Viene scelto il primo tipo in questo elenco per il quale esiste una conversione implicita. [...]

12.8.16 Operatori di incremento e decremento postfissi

La risoluzione dell'overload di un operatore unario viene applicata per selezionare una specifica implementazione dell'operatore. Esistono operatori predefiniti ++ e -- per i tipi seguenti: sbyte, byte, short, ushort, int, uint, nint, nuint,long, ulong, char, float, double, decimale qualsiasi tipo di enumerazione.

Operatore 12.9.2 Unary plus

Gli operatori unari più predefiniti sono:

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

12.9.3 Operatore unario meno

Gli operatori unari meno predefiniti sono:

  • Negazione integer:

    ...
    nint operator –(nint x);
    

12.8.16 Operatori di incremento e decremento postfissi

Esistono operatori predefiniti ++ e -- per i tipi seguenti: sbyte, byte, short, ushort, int, uint, nint, nuint, long, ulong, char, float, double, decimale qualsiasi tipo di enumerazione.

11.7.19 Espressioni di valore predefinite

Inoltre, un default_value_expression è un'espressione costante se il tipo è uno dei tipi di valore seguenti: sbyte, byte, short, ushort, int, uint, nint, nuint, long, ulong, char, float, double, decimal, bool, o qualsiasi tipo di enumerazione.

12.9.5 Operatore di complemento bit per bit

Gli operatori di complemento bit per bit predefiniti sono:

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

12.9.6 Operatori di incremento e decremento del prefisso

Esistono operatori predefiniti ++ e -- per i tipi seguenti: sbyte, byte, short, ushort, int, uint, nint, nuint, long, ulong, char, float, double, decimale qualsiasi tipo di enumerazione.

12.10 Operatori aritmetici

Operatore di moltiplicazione 12.10.2

Di seguito sono elencati gli operatori di moltiplicazione predefiniti. Tutti gli operatori calcolano il prodotto di x e y.

  • Moltiplicazione di numeri interi:

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

Operatore di divisione 12.10.3

Di seguito sono elencati gli operatori di divisione predefiniti. Tutti gli operatori calcolano il quoziente di x e y.

  • Divisione integer:

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

12.10.4 Operatore di resto

Di seguito sono elencati gli operatori di resto predefiniti. Tutti gli operatori calcolano il resto della divisione tra x e y.

  • Resto intero:

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

12.10.5 Operatore di somma

  • Addizione di numeri interi:

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

12.10.6 Operatore di sottrazione

  • Sottrazione integer:

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

12.11 Operatori shift

Di seguito sono elencati gli operatori di spostamento predefiniti.

  • Sposta a sinistra:

    ...
    nint operator <<(nint x, int count);
    nuint operator <<(nuint x, int count);
    
  • Sposta a destra

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

    L'operatore >> sposta x a destra di un numero di bit calcolato come descritto di seguito.

    Quando x è di tipo int, nint o long, i bit di ordine ridotto di x vengono rimossi, i bit rimanenti vengono spostati verso destra e le posizioni di bit vuote dell'ordine elevato vengono impostate su zero se x è non negativo e impostato su uno se x è negativo.

    Quando x è di tipo uint, nuint o ulong, i bit di ordine ridotto di x vengono rimossi, i bit rimanenti vengono spostati verso destra e le posizioni dei bit vuoti dell'ordine elevato vengono impostate su zero.

  • Spostamento senza segno a destra:

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

Per gli operatori predefiniti, il numero di bit da spostare viene calcolato nel modo seguente: [...]

  • Quando il tipo di x è nint o nuint, il conteggio dello spostamento è determinato dai cinque bit meno significativi di count su una piattaforma a 32 bit, oppure dai sei bit meno significativi di count su una piattaforma a 64 bit.

12.12 Operatori relazionali e di test dei tipi

12.12.2 Operatori di confronto integer

Gli operatori di confronto integer predefiniti sono:

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

12.12.2 Operatori logici Integer

Gli operatori logici integer predefiniti sono:

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

12.22 Espressioni costanti

Un'espressione costante può essere un tipo valore o un tipo riferimento. Se un'espressione costante è un tipo valore, deve essere uno dei tipi seguenti: sbyte, byte, short, ushort, int, uint, nint, nuint, long, ulong, char, float, double, decimal, bool, o qualsiasi tipo di enumerazione.

[...]

Una conversione implicita di espressioni costanti consente la conversione di un'espressione costante di tipo int in sbyte, byte, short, ushort, uint, nint, nuint, o ulong, purché il valore dell'espressione costante sia compreso nell'intervallo del tipo di destinazione.

17.4 Accesso agli elementi di un array

È possibile accedere agli elementi di matrice usando element_access espressioni del form A[I₁, I₂, ..., Iₓ], dove A è un'espressione di un tipo di matrice e ogni Iₑ è un'espressione di tipo int, uint, nint, nuint,long, ulongo può essere convertita in modo implicito in uno o più di questi tipi. Il risultato dell'accesso a un elemento di matrice è una variabile, ovvero l'elemento della matrice selezionato dagli indici.

23.5 Conversioni dei puntatori

23.5.1 Generale

[...]

Inoltre, in un contesto non sicuro, il set di conversioni esplicite disponibili viene esteso per includere le seguenti conversioni esplicite di puntatore:

  • Da qualsiasi pointer_type a qualsiasi altro pointer_type.
  • Da sbyte, byte, short, ushort, int, uint, ,nint, nuint,,longo ulong a qualsiasi pointer_type.
  • Da qualsiasi pointer_type a sbyte, byte, short, ushort, int, uint, nint, nuint,longo ulong.

23.6.4 Accesso all'elemento puntatore

In un accesso a un elemento puntatore del tipo P[E], P deve essere un'espressione di tipo puntatore diverso da void*e E deve essere un'espressione che può essere convertita in modo implicito in int, uint, nint, nuint,longo ulong.

23.6.7 Aritmetica del puntatore

In un contesto non sicuro, l'operatore + e l'operatore possono essere applicati ai valori di tutti i tipi di puntatore tranne void*. Di conseguenza, per ogni tipo di puntatore T*, gli operatori seguenti vengono definiti in modo implicito:

[...]
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);

Data un'espressione P di un tipo puntatore T* e un'espressione N di tipo int, uint, nint, nuint,longo ulong, le espressioni P + N e N + P calcolano il valore del puntatore di tipo T* risultante dall'aggiunta di N * sizeof(T) all'indirizzo specificato da P. Analogamente, l'espressione P – N calcola il valore del puntatore di tipo T* risultante dalla sottrazione di N * sizeof(T) dall'indirizzo specificato da P.

Varie considerazioni

Modifiche di rilievo

Uno degli effetti principali di questo design è che System.IntPtr e System.UIntPtr ottengono alcuni operatori incorporati (conversioni, unari e binari).
Tali operatori includono gli operatori checked, il che significa che gli operatori seguenti su tali tipi ora genereranno un'eccezione in caso di overflow:

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

Codifica dei metadati

Questo design significa che nint e nuint possono essere semplicemente generati come System.IntPtr e System.UIntPtr, senza l'uso di System.Runtime.CompilerServices.NativeIntegerAttribute.
Allo stesso modo, caricando i metadati, si può ignorare NativeIntegerAttribute.