IntPtr numérico
Observação
Este artigo é uma especificação de recurso. A especificação serve como o documento de design para o recurso. Ele inclui mudanças de especificação propostas, juntamente com as informações necessárias durante o design e desenvolvimento do recurso. Estes artigos são publicados até que as alterações de especificações propostas sejam finalizadas e incorporadas na especificação ECMA atual.
Pode haver algumas discrepâncias entre a especificação do recurso e a implementação concluída. Essas diferenças são capturadas nas notas pertinentes da Language Design Meeting (LDM).
Você pode saber mais sobre o processo de adoção de especificações de recursos no padrão de linguagem C# no artigo sobre as especificações .
Resumo
Esta é uma revisão no recurso inicial de inteiros nativos (spec), onde os tipos de nint
/nuint
eram distintos dos tipos subjacentes System.IntPtr
/System.UIntPtr
.
Em suma, agora tratamos nint
/nuint
como tipos simples que aliasam System.IntPtr
/System.UIntPtr
, como fazemos para int
em relação a System.Int32
. O sinalizador de tempo de execução System.Runtime.CompilerServices.RuntimeFeature.NumericIntPtr
aciona este novo comportamento.
Desenho
8.3.5 Tipos simples
C# fornece um conjunto de tipos de struct
predefinidos chamados de tipos simples. Os tipos simples são identificados por meio de palavras-chave, mas essas palavras-chave são simplesmente aliases para tipos de struct
predefinidos no namespace System
, conforme descrito na tabela abaixo.
palavra-chave | Tipo aliased |
---|---|
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 integrais
O C# suporta onze tipos integrais: sbyte
, byte
, short
, ushort
, int
, uint
, nint
, nuint
, long
, ulong
e char
. [...]
8.8 Tipos não gerenciados
Por outras palavras, um unmanaged_type é um dos seguintes:
-
sbyte
,byte
,short
,ushort
,int
,uint
,nint
,nuint
,long
,ulong
,char
,float
,double
,decimal
oubool
. - Qualquer enum_type.
- Qualquer struct_type definido pelo usuário que não seja um tipo construído e contenha apenas campos de unmanaged_types.
- Em código inseguro, qualquer pointer_type.
10.2.3 Conversões numéricas implícitas
As conversões numéricas implícitas são:
- De
sbyte
ashort
,int
,nint
,long
,float
,double
oudecimal
. - De
byte
ashort
,ushort
,int
,uint
,nint
,nuint
,long
,ulong
,float
,double
oudecimal
. - De
short
aint
,nint
,long
,float
,double
, oudecimal
. - De
ushort
aint
,uint
,nint
,nuint
,long
,ulong
,float
,double
oudecimal
. - De
int
anint
,long
,float
,double
oudecimal
. - De
uint
anuint
,long
,ulong
,float
,double
, oudecimal
. -
De
nint
along
,float
,double
oudecimal
. -
De
nuint
aulong
,float
,double
oudecimal
. - De
long
afloat
,double
oudecimal
. - De
ulong
afloat
,double
oudecimal
. - De
char
aushort
,int
,uint
,nint
,nuint
,long
,ulong
,float
,double
oudecimal
. - De
float
adouble
.
[...]
10.2.11 Conversões implícitas de expressões constantes
Uma conversão de expressão constante implícita permite as seguintes conversões:
- Uma constant_expression do tipo
int
pode ser convertida em tiposbyte
,byte
,short
,ushort
,uint
,nint
,nuint
ouulong
, desde que o valor do constant_expression esteja dentro do intervalo do tipo de destino. [...]
10.3.2 Conversões numéricas explícitas
As conversões numéricas explícitas são as conversões de um numeric_type para outro numeric_type para as quais ainda não existe uma conversão numérica implícita:
- De
sbyte
abyte
,ushort
,uint
,nuint
,ulong
, ouchar
. - De
byte
asbyte
ouchar
. - De
short
asbyte
,byte
,ushort
,uint
,nuint
,ulong
ouchar
. - De
ushort
asbyte
,byte
,short
ouchar
. - De
int
asbyte
,byte
,short
,ushort
,uint
,nuint
,ulong
ouchar
. - De
uint
asbyte
,byte
,short
,ushort
,int
,nint
ouchar
. - De
long
asbyte
,byte
,short
,ushort
,int
,uint
,nint
,nuint
,ulong
ouchar
. -
De
nint
asbyte
,byte
,short
,ushort
,int
,uint
,nuint
,ulong
ouchar
. -
De
nuint
asbyte
,byte
,short
,ushort
,int
,uint
,nint
,long
ouchar
. - De
ulong
asbyte
,byte
,short
,ushort
,int
,uint
,nint
,nuint
,long
ouchar
. - De
char
asbyte
,byte
oushort
. - De
float
asbyte
,byte
,short
,ushort
,int
,uint
,nint
,nuint
,long
,ulong
,char
oudecimal
. - De
double
asbyte
,byte
,short
,ushort
,int
,uint
,nint
,nuint
,long
,ulong
,char
,float
, oudecimal
. - De
decimal
asbyte
,byte
,short
,ushort
,int
,uint
,nint
,nuint
,long
,ulong
,char
,float
, oudouble
.
[...]
10.3.3 Conversões de enumeração explícitas
As conversões de enumeração explícitas são:
- De
sbyte
,byte
,short
,ushort
,int
,uint
,nint
,nuint
,long
,ulong
,char
,float
,double
oudecimal
a qualquer enum_type. - De qualquer enum_type a
sbyte
,byte
,short
,ushort
,int
,uint
,nint
,nuint
,long
,ulong
,char
,float
,double
oudecimal
. - De qualquer enum_type para qualquer outro enum_type.
12.6.4.7 Melhor objetivo de conversão
Dado os dois tipos T₁
e T₂
, T₁
é um alvo de conversão melhor do que T₂
se uma das seguintes condições for verdadeira:
- Existe uma conversão implícita de
T₁
paraT₂
e não existe conversão implícita deT₂
paraT₁
-
T₁
éTask<S₁>
,T₂
éTask<S₂>
eS₁
é um alvo de conversão melhor do queS₂
-
T₁
éS₁
ouS₁?
ondeS₁
é um tipo integral assinado, eT₂
éS₂
ouS₂?
ondeS₂
é um tipo integral não assinado. Mais especificamente: [...]
12.8.12 Acesso a elementos
[...] O número de expressões no argument_list deve ser igual ao da array_typee cada expressão deve ser do tipo int
, uint
, nint
, nuint
, long
, ou ulong,
ou deve ser implicitamente convertível num ou mais destes tipos.
11.8.12.2 Acesso ao array
[...] O número de expressões no argument_list deve ser igual ao da array_typee cada expressão deve ser do tipo int
, uint
, nint
, nuint
, long
, ou ulong,
ou deve ser implicitamente convertível num ou mais destes tipos.
O processamento em tempo de execução de um acesso a matriz da forma P[A]
, onde P
é uma primary_no_array_creation_expression de um array_type e A
é um argument_list, consiste nas seguintes etapas:
- As expressões índice do argument_list são avaliadas em ordem, da esquerda para a direita. Após a avaliação de cada expressão de índice, é realizada uma conversão implícita para um dos seguintes tipos:
int
,uint
,nint
,nuint
,long
,ulong
. Escolhe-se o primeiro tipo desta lista para o qual existe uma conversão implícita. [...]
12.8.16 Operadores de incremento e decréscimo em Postfix
A resolução de sobrecarga do operador unário é aplicada para selecionar uma implementação específica do operador. Existem operadores de ++
e --
predefinidos para os seguintes tipos: sbyte
, byte
, short
, ushort
, int
, uint
, nint
, nuint
,long
, ulong
, char
, float
, double
, decimal
e qualquer tipo de enum.
12.9.2 Operador Unary plus
Os operadores unary plus predefinidos são:
...
nint operator +(nint x);
nuint operator +(nuint x);
12.9.3 Unary menos operador
Os operadores menos unários predefinidos são:
Negação inteira:
... nint operator –(nint x);
12.8.16 Operadores de incremento e decréscimo em Postfix
Existem operadores de ++
e --
predefinidos para os seguintes tipos: sbyte
, byte
, short
, ushort
, int
, uint
, nint
, nuint
, long
, ulong
, char
, float
, double
, decimal
e qualquer tipo de enum.
11.7.19 Expressões de valor padrão
Além disso, um default_value_expression é uma expressão constante se o tipo for um dos seguintes tipos de valor: sbyte
, byte
, short
, ushort
, int
, uint
, nint
, nuint
, long
, ulong
, char
, float
, double
, decimal
, bool,
ou qualquer tipo de enumeração.
12.9.5 Operador do complemento Bitwise
Os operadores predefinidos de complemento a nível de bits são:
...
nint operator ~(nint x);
nuint operator ~(nuint x);
12.9.6 Operadores de incremento e decréscimo de prefixo
Existem operadores de ++
e --
predefinidos para os seguintes tipos: sbyte
, byte
, short
, ushort
, int
, uint
, nint
, nuint
, long
, ulong
, char
, float
, double
, decimal
e qualquer tipo de enum.
12.10 Operadores aritméticos
12.10.2 Operador de multiplicação
Os operadores de multiplicação predefinidos estão listados abaixo. Todos os operadores calculam o produto de x
e y
.
Multiplicação inteira:
... nint operator *(nint x, nint y); nuint operator *(nuint x, nuint y);
12.10.3 Operador de divisão
Os operadores de divisão predefinidos estão listados abaixo. Todos os operadores calculam o quociente de x
e y
.
Divisão inteira:
... nint operator /(nint x, nint y); nuint operator /(nuint x, nuint y);
12.10.4 Operador remanescente
Os restantes operadores predefinidos estão listados abaixo. Todos os operadores calculam o restante da divisão entre x
e y
.
Inteiro restante:
... nint operator %(nint x, nint y); nuint operator %(nuint x, nuint y);
12.10.5 Operador de adição
Adição de inteiros:
... nint operator +(nint x, nint y); nuint operator +(nuint x, nuint y);
12.10.6 Operador de subtração
Subtração inteira:
... nint operator –(nint x, nint y); nuint operator –(nuint x, nuint y);
12.11 Operadores de turnos
Os operadores de turnos predefinidos estão listados abaixo.
Vire para a esquerda:
... nint operator <<(nint x, int count); nuint operator <<(nuint x, int count);
Vire para a direita:
... nint operator >>(nint x, int count); nuint operator >>(nuint x, int count);
O operador
>>
deslocax
para a direita por um número de bits calculado conforme descrito abaixo.Quando
x
é do tipoint
,nint
oulong
, os bits de ordem baixa dex
são descartados, os bits restantes são deslocados para a direita e as posições de bits vazios de ordem alta são definidas como zero sex
não for negativo e definidas como uma sex
for negativo.Quando
x
é do tipouint
,nuint
ouulong
, os bits de ordem baixa dex
são descartados, os bits restantes são deslocados para a direita e as posições de bits vazios de ordem alta são definidas como zero.Deslocamento não assinado para a direita:
... nint operator >>>(nint x, int count); nuint operator >>>(nuint x, int count);
Para os operadores predefinidos, o número de bits a deslocar é calculado da seguinte forma: [...]
- Quando o tipo de
x
énint
ounuint
, a contagem de turnos é dada pelos cinco bits decount
de ordem baixa em uma plataforma de 32 bits ou os seis bits decount
de ordem inferior em uma plataforma de 64 bits.
12.12 Operadores de ensaios relacionais e de tipo
12.12.2 Operadores de comparação de números inteiros
Os operadores de comparação de inteiros predefinidos são:
...
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 inteiros
Os operadores lógicos inteiros predefinidos são:
...
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 Expressões constantes
Uma expressão constante pode ser um tipo de valor ou um tipo de referência. Se uma expressão constante for um tipo de valor, ela deve ser um dos seguintes tipos: sbyte
, byte
, short
, ushort
, int
, uint
, nint
, nuint
, long
, ulong
, char
, float
, double
, decimal
, bool,
ou qualquer tipo de enumeração.
[...]
Uma conversão de expressão constante implícita permite que uma expressão constante do tipo int
seja convertida em sbyte
, byte
, short
, ushort
, uint
, nint
, nuint
, ou ulong
, desde que o valor da expressão constante esteja dentro do intervalo do tipo de destino.
17.4 Acesso a elementos de matriz
Os elementos da matriz são acessados usando expressões element_access do formulário A[I₁, I₂, ..., Iₓ]
, onde A
é uma expressão de um tipo de matriz e cada Iₑ
é uma expressão do tipo int
, uint
, nint
, nuint
,long
, ulong
, ou pode ser implicitamente convertido em um ou mais desses tipos. O resultado de um acesso a um elemento de matriz é uma variável, ou seja, o elemento de matriz selecionado pelos índices.
23.5 Conversões de ponteiro
23.5.1 Generalidades
[...]
Além disso, em um contexto inseguro, o conjunto de conversões explícitas disponíveis é estendido para incluir as seguintes conversões de ponteiro explícito:
- De qualquer pointer_type para qualquer outra pointer_type.
- De
sbyte
,byte
,short
,ushort
,int
,uint
,nint
,nuint
,long
ouulong
a qualquer pointer_type. - De qualquer pointer_type a
sbyte
,byte
,short
,ushort
,int
,uint
,nint
,nuint
,long
ouulong
.
23.6.4 Acesso ao elemento de ponteiro
No acesso a um elemento de ponteiro na forma P[E]
, P
deve ser uma expressão de um tipo de ponteiro diferente daquele de void*
, e E
deve ser uma expressão que pode ser implicitamente convertida em int
, uint
, nint
, nuint
,long
ou ulong
.
23.6.7 Aritmética dos ponteiros
Em um contexto inseguro, o operador +
e o operador –
podem ser aplicados a valores de todos os tipos de ponteiro, exceto void*
. Assim, para cada tipo de ponteiro T*
, os seguintes operadores são implicitamente 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 uma expressão P
de um tipo de ponteiro T*
e de uma expressão N
do tipo int
, uint
, nint
, nuint
,long
ou ulong
, as expressões P + N
e N + P
calculam o valor do ponteiro do tipo T*
que resulta da adição de N * sizeof(T)
ao endereço fornecido por P
. Da mesma forma, a expressão P – N
calcula o valor de ponteiro do tipo T*
que resulta da subtração N * sizeof(T)
do endereço fornecido por P
.
Várias considerações
Mudanças significativas
Um dos principais impactos deste design é que System.IntPtr
e System.UIntPtr
ganham alguns operadores embutidos (conversões, unários e binários).
Estes incluem operadores checked
, o que significa que os seguintes operadores nesses tipos irão agora lançar quando transbordarem:
IntPtr + int
IntPtr - int
IntPtr -> int
long -> IntPtr
void* -> IntPtr
Codificação de metadados
Este design significa que nint
e nuint
podem simplesmente ser emitidos como System.IntPtr
e System.UIntPtr
, sem o uso de System.Runtime.CompilerServices.NativeIntegerAttribute
.
Da mesma forma, ao carregar metadados NativeIntegerAttribute
pode ser ignorado.
C# feature specifications