IntPtr numérico
Nota:
Este artículo es una especificación de características. La especificación actúa como documento de diseño de la característica. Incluye cambios de especificación propuestos, junto con la información necesaria durante el diseño y el desarrollo de la característica. Estos artículos se publican hasta que se finalizan los cambios de especificación propuestos y se incorporan en la especificación ECMA actual.
Puede haber algunas discrepancias entre la especificación de características y la implementación completada. Esas diferencias se recogen en las notas de la reunión de diseño de lenguaje (LDM) correspondientes.
Puede obtener más información sobre el proceso de adopción de especificaciones de características en el estándar del lenguaje C#, en el artículo sobre especificaciones.
Problema planteado por el experto: https://github.com/dotnet/csharplang/issues/6065
Resumen
Esta es una revisión de la característica inicial de enteros nativos (spec), donde los tipos nint
/nuint
eran distintos de los tipos subyacentes System.IntPtr
/System.UIntPtr
.
En resumen, ahora tratamos nint
/nuint
como tipos simples aliasing System.IntPtr
/System.UIntPtr
, como hacemos para int
en relación a System.Int32
. El indicador de características de tiempo de ejecución System.Runtime.CompilerServices.RuntimeFeature.NumericIntPtr
desencadena este nuevo comportamiento.
Diseño
8.3.5 Tipos simples
C# proporciona un conjunto de tipos struct
predefinidos llamados tipos simples. Los tipos simples se identifican mediante palabras clave, pero estas palabras clave son simplemente alias de tipos predefinidos de struct
en el espacio de nombres System
, como se describe en la tabla siguiente.
palabra clave | Tipo de 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 Tipos integrales
C# admite once tipos integrales: sbyte
, byte
, short
, ushort
, int
, uint
, nint
, nuint
, long
, ulong
y char
. [...]
8.8 Tipos no administrados
En otras palabras, un unmanaged_type es uno de los siguientes:
-
sbyte
,byte
,short
,ushort
,int
,uint
,nint
,nuint
,long
,ulong
,char
,float
,double
,decimal
obool
. - Cualquier enum_type.
- Cualquier struct_type que no sea un tipo construido y contenga campos de unmanaged_types solamente.
- En código inseguro, cualquier pointer_type.
10.2.3 Conversiones numéricas implícitas
Las conversiones numéricas implícitas son:
- De
sbyte
ashort
,int
,nint
,long
,float
,double
odecimal
. - De
byte
ashort
,ushort
,int
,uint
,nint
,nuint
,long
,ulong
,float
,double
odecimal
. - De
short
aint
,nint
,long
,float
,double
odecimal
. - De
ushort
aint
,uint
,nint
,nuint
,long
,ulong
,float
,double
odecimal
. - De
int
anint
,long
,float
,double
odecimal
. - De
uint
anuint
,long
,ulong
,float
,double
odecimal
. - De
nint
along
,float
,double
odecimal
. - De
nuint
aulong
,float
,double
odecimal
. - De
long
afloat
,double
odecimal
. - De
ulong
afloat
,double
odecimal
. - De
char
aushort
,int
,uint
,nint
,nuint
,long
,ulong
,float
,double
odecimal
. - De
float
adouble
.
[...]
10.2.11 Conversiones de expresiones constantes implícitas
Una conversión de expresión constante implícita permite las siguientes conversiones:
- Una constant_expression de tipo
int
se puede convertir a tiposbyte
,byte
,short
,ushort
,uint
,nint
,nuint
oulong
, siempre que el valor de la constant_expression esté dentro del rango del tipo de destino. [...]
10.3.2 Conversiones numéricas explícitas
Las conversiones numéricas explícitas son las conversiones de un numeric_type a otro numeric_type para el que no existe ya una conversión numérica implícita:
- De
sbyte
abyte
,ushort
,uint
,nuint
,ulong
ochar
. - De
byte
asbyte
ochar
. - De
short
asbyte
,byte
,ushort
,uint
,nuint
,ulong
ochar
. - De
ushort
asbyte
,byte
,short
ochar
. - De
int
asbyte
,byte
,short
,ushort
,uint
,nuint
,ulong
ochar
. - De
uint
asbyte
,byte
,short
,ushort
,int
,nint
ochar
. - De
long
asbyte
,byte
,short
,ushort
,int
,uint
,nint
,nuint
,ulong
ochar
. - De
nint
asbyte
,byte
,short
,ushort
,int
,uint
,nuint
,ulong
, ochar
. - De
nuint
asbyte
,byte
,short
,ushort
,int
,uint
,nint
,long
, ochar
. - De
ulong
asbyte
,byte
,short
,ushort
,int
,uint
,nint
,nuint
,long
ochar
. - De
char
asbyte
,byte
oshort
. - De
float
asbyte
,byte
,short
,ushort
,int
,uint
,nint
,nuint
,long
,ulong
,char
odecimal
. - De
double
asbyte
,byte
,short
,ushort
,int
,uint
,nint
,nuint
,long
,ulong
,char
,float
odecimal
. - De
decimal
asbyte
,byte
,short
,ushort
,int
,uint
,nint
,nuint
,long
,ulong
,char
,float
odouble
.
[...]
10.3.3 Conversiones de enumeración explícitas
Las conversiones explícitas de enumeración son:
- Desde
sbyte
,byte
,short
,ushort
,int
,uint
,nint
,nuint
,long
,ulong
,char
,float
,double
odecimal
a cualquier enum_type. - Desde cualquier enum_type a
sbyte
,byte
,short
,ushort
,int
,uint
,nint
,nuint
,long
,ulong
,char
,float
,double
odecimal
. - De cualquier enum_type a cualquier otro enum_type.
12.6.4.7 Mejor objetivo de conversión
Dados dos tipos T₁
y T₂
, T₁
es un mejor destino de conversión que T₂
si se cumple una de las siguientes condiciones:
- Existe una conversión implícita de
T₁
aT₂
y no existe ninguna conversión implícita deT₂
aT₁
-
T₁
esTask<S₁>
,T₂
esTask<S₂>
yS₁
es un objetivo de conversión mejor queS₂
-
T₁
esS₁
oS₁?
dondeS₁
es un tipo entero con signo yT₂
esS₂
oS₂?
dondeS₂
es un tipo entero sin signo. Específicamente: [...]
12.8.12 Acceso a elementos
[...] El número de expresiones de la argument_list será el mismo que el rango del array_type, y cada expresión será del tipo int
, uint
, nint
, nuint
, long
o ulong,
o será implícitamente convertible a uno o más de estos tipos.
11.8.12.2 Acceso a matrices
[...] El número de expresiones de la argument_list será el mismo que el rango del array_type, y cada expresión será del tipo int
, uint
, nint
, nuint
, long
o ulong,
o será implícitamente convertible a uno o más de estos tipos.
[...] El procesamiento en tiempo de ejecución de un acceso a una matriz de la forma P[A]
, donde P
es una primary_no_array_creation_expression de un array_type y A
es una argument_list, consta de los siguientes pasos: [...]
- Las expresiones de índice de la argument_list se evalúan en orden, de izquierda a derecha. Tras la evaluación de cada expresión de índice, se realiza una conversión implícita a uno de los siguientes tipos:
int
,uint
,nint
,nuint
,long
,ulong
. Se elige el primer tipo de la lista para el que existe una conversión implícita. [...]
12.8.16 Operadores de incremento y decremento postfijos
La resolución de sobrecarga de operador unario se aplica para seleccionar una implementación de operador específica. Existen operadores predefinidos ++
y --
para los siguientes tipos: sbyte
, byte
, short
, ushort
, int
, uint
, nint
, nuint
,long
, ulong
, char
, float
, double
, decimal
y cualquier tipo enum.
12.9.2 Operador de suma unario
Los operadores más unarios predefinidos son:
...
nint operator +(nint x);
nuint operator +(nuint x);
12.9.3 Operador de resta unario
Los operadores menos unarios predefinidos son:
Negación de enteros:
... nint operator –(nint x);
12.8.16 Operadores de incremento y decremento postfijos
Existen operadores predefinidos ++
y --
para los siguientes tipos: sbyte
, byte
, short
, ushort
, int
, uint
, nint
, nuint
, long
, ulong
, char
, float
, double
, decimal
, y cualquier tipo enum.
11.7.19 Expresiones de valor por defecto
Además, un default_value_expression es una expresión constante si el tipo es uno de los siguientes tipos de valor: sbyte
, byte
, short
, ushort
, int
, uint
, nint
, nuint
, long
, ulong
, char
, float
, double
, decimal
, bool,
o cualquier tipo de enumeración.
12.9.5 Operador de complemento bit a bit
Los operadores de complemento a nivel de bit predefinidos son:
...
nint operator ~(nint x);
nuint operator ~(nuint x);
12.9.6 Operadores de incremento y decremento prefijos
Existen operadores predefinidos ++
y --
para los siguientes tipos: sbyte
, byte
, short
, ushort
, int
, uint
, nint
, nuint
, long
, ulong
, char
, float
, double
, decimal
, y cualquier tipo enum.
12.10 Operadores aritméticos
12.10.2 Operador de multiplicación
A continuación se enumeran los operadores de multiplicación predefinidos. Los operadores calculan el producto de x
y y
.
Multiplicación de enteros:
... nint operator *(nint x, nint y); nuint operator *(nuint x, nuint y);
12.10.3 Operador de división
A continuación se enumeran los operadores de división predefinidos. Todos los operadores calculan el cociente de x
y y
.
División entera:
... nint operator /(nint x, nint y); nuint operator /(nuint x, nuint y);
12.10.4 Operador de resto
A continuación se enumeran los operadores de resto predefinidos. Todos los operadores calculan el resto de la división entre x
y y
.
Resto entero:
... nint operator %(nint x, nint y); nuint operator %(nuint x, nuint y);
12.10.5 Operador de suma
Suma de números enteros:
... nint operator +(nint x, nint y); nuint operator +(nuint x, nuint y);
12.10.6 Operador de resta
Resta de números enteros:
... nint operator –(nint x, nint y); nuint operator –(nuint x, nuint y);
12.11 Operadores de desplazamiento
A continuación se enumeran los operadores de desplazamiento predefinidos.
Desplazamiento a la izquierda:
... nint operator <<(nint x, int count); nuint operator <<(nuint x, int count);
Desplazamiento a la derecha:
... nint operator >>(nint x, int count); nuint operator >>(nuint x, int count);
El operador
>>
desplazax
hacia la derecha por un número de bits calculado como se describe a continuación.Cuando
x
es del tipoint
,nint
olong
, los bits de orden inferior dex
se descartan, los bits restantes se desplazan a la derecha y las posiciones de bits vacías de orden superior se ponen a cero six
es no negativo y a uno six
es negativo.Cuando
x
es de tipouint
,nuint
oulong
, los bits de orden inferior dex
se descartan, los bits restantes se desplazan a la derecha y las posiciones de bits vacíos de orden superior se ponen a cero.Desplazamiento sin signo a la derecha:
... nint operator >>>(nint x, int count); nuint operator >>>(nuint x, int count);
Para los operadores predefinidos, el número de bits a desplazar se calcula como sigue: [...]
- Cuando el tipo de
x
esnint
onuint
, el número de bits a desplazar viene dado por los cinco bits de orden inferior decount
en una plataforma de 32 bits, o los seis bits de orden inferior decount
en una plataforma de 64 bits.
12.12 Operadores relacionales y de comprobación de tipo
12.12.2 Operadores de comparación de enteros
Los operadores de comparación de enteros predefinidos son:
...
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 Operadores lógicos
12.12.2 Operadores lógicos de enteros
Los operadores lógicos de enteros predefinidos son:
...
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 Expresiones constantes
Una expresión constante puede ser de tipo valor o de tipo referencia. Si una expresión constante es un tipo de valor, debe ser uno de los siguientes tipos: sbyte
, byte
, short
, ushort
, int
, uint
, nint
, nuint
, long
, ulong
, char
, float
, double
, decimal
, bool,
o cualquier tipo de enumeración.
[...]
Una conversión implícita de expresiones constantes permite convertir una expresión constante de tipo int
a sbyte
, byte
, short
, ushort
, uint
, nint
, nuint
, o ulong
o , siempre que el valor de la expresión constante esté dentro del rango del tipo de destino.
17.4 Acceso a elementos del array
Para acceder a los elementos de una matriz se utilizan expresiones element_access de la forma A[I₁, I₂, ..., Iₓ]
, donde A
es una expresión de tipo matriz y cada Iₑ
es una expresión de tipo int
, uint
, nint
, nuint
,long
, ulong
o puede convertirse implícitamente a uno o varios de estos tipos. El resultado de un acceso a un elemento del array es una variable, a saber, el elemento del array seleccionado por los índices.
23.5 Conversiones de punteros
23.5.1 General
[...]
Además, en un contexto inseguro, el conjunto de conversiones explícitas disponibles se amplía para incluir las siguientes conversiones explícitas de punteros:
- De cualquier tipo_de_puntero a cualquier otro tipo_de_puntero .
- De
sbyte
,byte
,short
,ushort
,int
,uint
,nint
,nuint
,long
oulong
a cualquier pointer_type. - De cualquier pointer_type a
sbyte
,byte
,short
,ushort
,int
,uint
,nint
,nuint
,long
oulong
.
23.6.4 Acceso a elementos de puntero
[...] En un acceso a un elemento puntero de la forma P[E]
, P
deberá ser una expresión de un tipo puntero distinto de void*
, y E
deberá ser una expresión que pueda ser convertida implícitamente a int
, uint
, nint
, nuint
,long
o ulong
.
23.6.7 Aritmética de punteros
En un contexto inseguro, el operador +
y el operador –
pueden aplicarse a valores de todos los tipos de puntero excepto void*
. Así, para cada tipo de puntero T*
, los siguientes operadores están implícitamente definidos:
[...]
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);
Dada una expresión P
de tipo puntero T*
y una expresión N
de tipo int
, uint
, nint
, nuint
,long
o ulong
, las expresiones P + N
y N + P
calculan el valor puntero de tipo T*
que resulta de sumar N * sizeof(T)
a la dirección dada por P
. Del mismo modo, la expresión P – N
calcula el valor del puntero de tipo T*
que resulta de restar N * sizeof(T)
de la dirección dada por P
.
Consideraciones varias
Cambios importantes
Uno de los principales impactos de este diseño es que System.IntPtr
y System.UIntPtr
obtienen algunos operadores integrados (conversiones, unarios y binarios).
Entre ellos se incluyen operadores checked
, que significa que los siguientes operadores de esos tipos ahora se iniciarán al desbordarse:
IntPtr + int
IntPtr - int
IntPtr -> int
long -> IntPtr
void* -> IntPtr
Codificación de metadatos
Este diseño significa que nint
y nuint
pueden emitirse simplemente como System.IntPtr
y System.UIntPtr
, sin utilizar System.Runtime.CompilerServices.NativeIntegerAttribute
.
Del mismo modo, al cargar metadatos NativeIntegerAttribute
puede ser omitido.
C# feature specifications