Exatamente o que é um IntPtr exatamente?


171

Usando o IntelliSense e analisando o código de outras pessoas, deparei-me com esse IntPtrtipo; toda vez que ele precisou ser usado, simplesmente coloquei nullou IntPtr.Zeroencontrei a maioria das funções para trabalhar. O que exatamente é e quando / por que é usado?

Respostas:


158

É um "número inteiro de tamanho nativo (específico da plataforma)". É representado internamente como void*exposto como um número inteiro. Você pode usá-lo sempre que precisar armazenar um ponteiro não gerenciado e não desejar usar unsafecódigo. IntPtr.Zeroé efetivamente NULL(um ponteiro nulo).


53
Um ponteiro é algo que aponta para um endereço na memória. Em linguagens gerenciadas você tem referências (o endereço pode se mover), enquanto em línguas não gerenciados você tem ponteiros (o endereço é fixo)
Colin Mackay

93
Em geral (nas linguagens de programação), um ponteiro é um número que representa um local físico na memória. Um ponteiro nulo é (quase sempre) um que aponta para 0 e é amplamente reconhecido como "não apontando para nada". Como os sistemas possuem quantidades diferentes de memória suportada, nem sempre é necessário o mesmo número de bytes para armazenar esse número, por isso chamamos um número inteiro de "tamanho nativo" que pode conter um ponteiro em qualquer sistema específico.
21320 Sam Harwell

5
+1 para esse comentário @ 280Z28, essa é a explicação mais sucinta dos indicadores que eu já vi.
BlueRaja - Danny Pflughoeft

9
É chamado IntPtr, porque para usá-lo a partir de código nativo não gerenciado, C / C ++, você precisará usar o tipo analógico: intptr_t. O IntPtr do C # mapeia exatamente para o intptr_t do C / C ++. E provavelmente é implementado como intptr_t. No C / C ++, é garantido que o tipo intptr_t seja do mesmo tamanho que o tipo void *.
Петър Петров

2
@Trap "Um tipo específico de plataforma usado para representar um ponteiro ou um identificador." Não é um "número inteiro específico da plataforma", uma "maneira específica da plataforma de representar um ponteiro ou um identificador". IntPtrfaz todo o sentido, porque é um número inteiro (como em número inteiro matemático) e um ponteiro (como em ponteiro). A Intparte tem pouco a ver com o tipo int - é um conceito, não um tipo específico. Embora seja justo, a única coisa que a especificação da CLI diz sobre isso é que realmente é um "tamanho inteiro, nativo". Oh bem :)
Luaan

69

É um tipo de valor grande o suficiente para armazenar um endereço de memória usado em código nativo ou não seguro, mas não pode ser usado diretamente como endereço de memória em código gerenciado seguro.

Você pode IntPtr.Sizedescobrir se está executando um processo de 32 ou 64 bits, pois serão 4 ou 8 bytes, respectivamente.


16
Bom ponto sobre a detecção do tamanho do espaço de endereço para o processo.
Noldorin

@Noldorin True, mas não necessariamente confiável. No passado, havia muitas arquiteturas que tinham vários tipos de ponteiros, e no Windows IntPtrtambém é usado para representar identificadores de 32 bits, independentemente da arquitetura (embora Sizeainda seja 8 nesse caso). A especificação da CLI apenas observa que é um número inteiro de "tamanho nativo", mas isso não diz muito, na verdade.
Luaan 14/09/16

@Luaan que realmente não muda nada na minha resposta, muda? O IntPtr é chamado (e é usado em toda a origem do CLR) como um valor grande o suficiente para armazenar um endereço de memória. Pode conter valores menores, é claro. Algumas arquiteturas têm vários tipos de ponteiro, mas devem ter uma que seja a maior do conjunto.
21118 Daniel Earwicker

@DanielEarwicker Bem, até onde eu sei, não há problema com nenhuma implementação atual do .NET. No entanto, a questão (histórica) não se resume apenas ao tamanho - os vários indicadores podem ser totalmente incompatíveis. Em um exemplo mais próximo de hoje, o PAE usaria endereços de 64 bits, embora o "tamanho do ponteiro nativo" ainda fosse de 32 bits. Ela remonta ao argumento "o que significa 'sistema de 32 bits' realmente significa?" Agora temos registros numéricos de 256 e 512 bits, mas ainda o chamamos de 64 bits. Mesmo que você não consiga endereçar 64 bits de memória física com seus "ponteiros" de 64 bits. É uma bagunça.
Luaan 14/09/16

1
Algumas são complicadas, mas o IntPtr ainda é "um tipo de valor grande o suficiente para armazenar um endereço de memória". Não é tão grande quanto o maior registro de hardware, para dar um de seus exemplos. Não é para isso que serve. É grande o suficiente para representar um endereço de memória. Depois, existem coisas como esta: stackoverflow.com/questions/12006854/… onde a palavra "ponteiro" está sendo usada para algo que não seja um endereço de memória - e foi por isso que eu disse especificamente "endereço de memória".
21118 Daniel Earwicker

48

Aqui está um exemplo:

Estou escrevendo um programa em C # que faz interface com uma câmera de alta velocidade. A câmera possui seu próprio driver que adquire imagens e as carrega na memória do computador automaticamente para mim.

Portanto, quando estou pronto para trazer a imagem mais recente para o meu programa, o driver da câmera fornece um IntPtr para onde a imagem JÁ está armazenada na memória física, para que eu não precise perder tempo / recursos criando outro bloco de memória para armazenar uma imagem que já esteja na memória. O IntPtr apenas me mostra onde a imagem já está.


7
Portanto, o IntPtr simple permite que você use um ponteiro não gerenciado (como o usado no driver da câmera) no código gerenciado?
Callum Rogers

5
Sim. Bem, nesse caso, provavelmente o driver da câmera usa drivers não gerenciados sob o capô, mas para operar corretamente no mundo somente gerenciado, ele fornece o IntPtr para permitir que eu trabalhe com os dados com segurança.
bufferz

3
Então, por que você não devolve apenas um fluxo (matriz de bytes)? Por que é inseguro ou incapaz de retornar o valor?
The Muffin Man

35

Uma interpretação direta

Um IntPtr é um número inteiro que é do mesmo tamanho que um ponteiro .

Você pode usar o IntPtr para armazenar um valor de ponteiro em um tipo não-ponteiro. Esse recurso é importante no .NET, pois o uso de ponteiros é altamente suscetível a erros e, portanto, ilegal na maioria dos contextos. Ao permitir que o valor do ponteiro seja armazenado em um tipo de dados "seguro", o encanamento entre segmentos de código não seguro pode ser implementado em código de alto nível mais seguro - ou mesmo em uma linguagem .NET que não oferece suporte direto a ponteiros.

O tamanho do IntPtr é específico da plataforma, mas esses detalhes raramente precisam ser considerados, pois o sistema usará automaticamente o tamanho correto.

O nome "IntPtr" é confuso - algo como Handlepoderia ter sido mais apropriado. Meu palpite inicial era que "IntPtr" era um ponteiro para um número inteiro. A documentação do IntPtr do MSDN entra em detalhes um tanto enigmáticos, sem fornecer muitas informações sobre o significado do nome.

Uma perspectiva alternativa

An IntPtré um ponteiro com duas limitações:

  1. Não pode ser desreferenciado diretamente
  2. Ele não sabe o tipo de dados para o qual aponta.

Em outras palavras, um IntPtré como um void*- mas com o recurso extra que ele pode (mas não deveria) ser usado para aritmética básica dos ponteiros.

Para desreferenciar um IntPtr, você pode convertê-lo em um ponteiro verdadeiro (uma operação que só pode ser executada em contextos "inseguros") ou passá-lo para uma rotina auxiliar, como as fornecidas pela InteropServices.Marshalclasse. O uso da Marshalclasse fornece a ilusão de segurança, pois não exige que você esteja em um contexto "inseguro" explícito. No entanto, não elimina o risco de travamento inerente ao uso de ponteiros.


2
Há algum precedente para o nome "intptr" do padrão C99 da linguagem de programação "C". linux.die.net/man/3/intptr_t .
Brent Bradburn

17

O que é um ponteiro?

Em todos os idiomas, um ponteiro é um tipo de variável que armazena um endereço de memória e você pode solicitar que eles digam o endereço para o qual estão apontando ou o valor no endereço para o qual estão apontando.

Um ponteiro pode ser pensado como uma espécie de marca de livro. Exceto que, em vez de ser usado para pular rapidamente para uma página de um livro, um ponteiro é usado para rastrear ou mapear blocos de memória.

Imagine a memória do seu programa precisamente como uma grande variedade de 65535 bytes.

Ponteiros apontam obedientemente

Os ponteiros lembram um endereço de memória cada e, portanto, apontam para um único endereço na memória.

Como um grupo, os ponteiros lembram e lembram endereços de memória, obedecendo a todos os seus comandos ad nauseum.

Você é o rei deles.

Ponteiros em c #

Especificamente em C #, um ponteiro é uma variável inteira que armazena um endereço de memória entre 0 e 65534.

Também específicos para C #, os ponteiros são do tipo int e, portanto, assinados.

Porém, você não pode usar endereços numerados negativamente, nem acessar um endereço acima de 65534. Qualquer tentativa de fazer isso lançará uma System.AccessViolationException.

Um ponteiro chamado MyPointer é declarado da seguinte forma:

int * MyPointer;

Um ponteiro em C # é um int, mas os endereços de memória em C # começam em 0 e se estendem até 65534.

Coisas pontudas devem ser manuseadas com cuidado especial

A palavra inseguro é a intenção de assustá-lo, e por uma razão muito boa: Os ponteiros são coisas pontiagudas e coisas pontiagudas por exemplo, espadas, machados, ponteiros, etc., devem ser manuseados com cuidado especial extra.

Os ponteiros dão ao programador controle rígido de um sistema. Portanto, é provável que os erros cometidos tenham conseqüências mais graves.

Para usar ponteiros, o código não seguro deve ser ativado nas propriedades do seu programa e os ponteiros devem ser usados ​​exclusivamente em métodos ou blocos marcados como não seguros.

Exemplo de um bloco não seguro

unsafe
{
    // Place code carefully and responsibly here.

}

Como usar ponteiros

Quando variáveis ​​ou objetos são declarados ou instanciados, eles são armazenados na memória.

  • Declare um ponteiro usando o prefixo do símbolo *.

int *MyPointer;

  • Para obter o endereço de uma variável, use o prefixo do símbolo &.

MyPointer = &MyVariable;

Depois que um endereço é atribuído a um ponteiro, o seguinte se aplica:

  • Sem prefixo * para se referir ao endereço de memória apontado como int.

MyPointer = &MyVariable; // Set MyPointer to point at MyVariable

  • Com * prefixo para obter o valor armazenado no endereço de memória que está sendo apontado.

"MyPointer is pointing at " + *MyPointer;

Como um ponteiro é uma variável que contém um endereço de memória, esse endereço de memória pode ser armazenado em uma variável de ponteiro.

Exemplo de ponteiros sendo usados ​​com cuidado e responsabilidade

    public unsafe void PointerTest()
    {
        int x = 100; // Create a variable named x

        int *MyPointer = &x; // Store the address of variable named x into the pointer named MyPointer

        textBox1.Text = ((int)MyPointer).ToString(); // Displays the memory address stored in pointer named MyPointer

        textBox2.Text = (*MyPointer).ToString(); // Displays the value of the variable named x via the pointer named MyPointer.

    }

Observe que o tipo do ponteiro é um int. Isso ocorre porque o C # interpreta os endereços de memória como números inteiros (int).

Por que é int em vez de uint?

Não há uma boa razão.

Por que usar ponteiros?

Os ponteiros são muito divertidos. Com grande parte do computador sendo controlado pela memória, os ponteiros capacitam o programador a ter mais controle da memória do programa.

Monitoramento de memória.

Use ponteiros para ler blocos de memória e monitorar como os valores apontados mudam ao longo do tempo.

Altere esses valores de maneira responsável e acompanhe como suas alterações afetam seu computador.


2
65534parece muito errado como um intervalo de ponteiro. Você deve fornecer uma referência.
Brent Bradburn

1
Votei nisso porque é um ótimo artigo explicando os indicadores. Gostaria de ver algumas referências às especificações que você mencionou (como comentado acima). Contudo; esta resposta não tem nada a ver com a pergunta. A questão era sobre System.IntPtr. Gostaria de ver a resposta atualizada no final explicando o que também é System.IntPtre como se relaciona a ponteiros inseguros em C #, por favor.
Michael Puckett II

7

MSDN nos diz:

O tipo IntPtr foi projetado para ser um número inteiro cujo tamanho é específico da plataforma. Ou seja, espera-se que uma instância desse tipo seja de 32 bits em hardware e sistemas operacionais de 32 bits e 64 bits em hardware e sistemas operacionais de 64 bits.

O tipo IntPtr pode ser usado por idiomas que suportam ponteiros e como um meio comum de se referir a dados entre idiomas que suportam e não suportam ponteiros.

Objetos IntPtr também podem ser usados ​​para conter alças. Por exemplo, as instâncias do IntPtr são usadas extensivamente na classe System.IO.FileStream para armazenar identificadores de arquivo.

O tipo IntPtr é compatível com CLS, enquanto o tipo UIntPtr não é. Somente o tipo IntPtr é usado no Common Language Runtime. O tipo UIntPtr é fornecido principalmente para manter a simetria arquitetônica com o tipo IntPtr.

http://msdn.microsoft.com/en-us/library/system.intptr(VS.71).aspx


5

Bem, esta é a página do MSDN que lida comIntPtr .

A primeira linha diz:

Um tipo específico de plataforma usado para representar um ponteiro ou um identificador.

Quanto ao ponteiro ou identificador, a página continua dizendo:

O tipo IntPtr pode ser usado por idiomas que suportam ponteiros e como um meio comum de se referir a dados entre idiomas que suportam e não suportam ponteiros.

Objetos IntPtr também podem ser usados ​​para conter alças. Por exemplo, as instâncias do IntPtr são usadas extensivamente na classe System.IO.FileStream para armazenar identificadores de arquivo.

Um ponteiro é uma referência a uma área da memória que contém alguns dados nos quais você está interessado.

Um identificador pode ser um identificador para um objeto e é passado entre métodos / classes quando os dois lados precisam acessar esse objeto.


2

An IntPtré um tipo de valor usado principalmente para armazenar endereços ou identificadores de memória. Um ponteiro é um endereço de memória. Um ponteiro pode ser digitado (por exemplo,int* ) ou sem tipo (por exemplo void*). Um identificador do Windows é um valor que geralmente tem o mesmo tamanho (ou menor) que um endereço de memória e representa um recurso do sistema (como um arquivo ou janela).

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.