¿Qué es exactamente un IntPtr?


171

Al usar IntelliSense y mirar el código de otras personas, me he encontrado con este IntPtrtipo; Cada vez que ha sido necesario utilizarlo, simplemente puse nullo IntPtr.Zeroencontré la mayoría de las funciones para trabajar. ¿Qué es exactamente y cuándo / por qué se usa?

Respuestas:


158

Es un "entero de tamaño nativo (específico de la plataforma)". Está representado internamente como void*pero expuesto como un número entero. Puede usarlo siempre que necesite almacenar un puntero no administrado y no quiera usar unsafecódigo. IntPtr.Zeroes efectivamente NULL(un puntero nulo).


53
Un puntero es algo que apunta a una dirección en la memoria. En lenguajes administrados tiene referencias (la dirección puede moverse), mientras que en las lenguas no administrados que tiene punteros (la dirección se fija)
Colin Mackay

93
En general (en todos los lenguajes de programación), un puntero es un número que representa una ubicación física en la memoria. Un puntero nulo es (casi siempre) uno que apunta a 0, y es ampliamente reconocido como "sin señalar nada". Dado que los sistemas tienen diferentes cantidades de memoria admitida, no siempre se necesita la misma cantidad de bytes para contener ese número, por lo que llamamos un "entero de tamaño nativo" que puede contener un puntero en cualquier sistema en particular.
Sam Harwell

55
+1 para ese comentario @ 280Z28, esa es la explicación más sucinta de los punteros que he visto.
BlueRaja - Danny Pflughoeft

9
Se llama IntPtr, porque para usarlo desde un código nativo no administrado, C / C ++, deberá usar el tipo analógico: intptr_t. IntPtr de C # se asigna exactamente a intptr_t de C / C ++. Y probablemente se implementa como intptr_t. En C / C ++, se garantiza que el tipo intptr_t tendrá el mismo tamaño que el tipo void *.
Петър Петров

2
@Trap "Un tipo específico de plataforma que se utiliza para representar un puntero o un identificador". No es un "entero específico de plataforma", una "forma específica de plataforma para representar un puntero o un identificador". IntPtrtiene mucho sentido, porque es un entero (como en un entero matemático) y un puntero (como en un puntero). La Intparte tiene poco que ver con el tipo int: es un concepto, no un tipo específico. Aunque para ser justos, lo único que dice la especificación CLI al respecto es que, de hecho, es un "tamaño entero, nativo". Oh bueno :)
Luaan

69

Es un tipo de valor lo suficientemente grande como para almacenar una dirección de memoria como se usa en código nativo o inseguro, pero no se puede usar directamente como una dirección de memoria en un código administrado seguro.

Puede IntPtr.Sizeaveriguar si está ejecutando un proceso de 32 bits o de 64 bits, ya que será de 4 u 8 bytes, respectivamente.


16
Buen punto sobre la detección del tamaño del espacio de direcciones para el proceso.
Noldorin

@Noldorin Cierto, pero no necesariamente confiable. En el pasado, ha habido muchas arquitecturas que tenían múltiples tipos de puntero, y en Windows, IntPtrtambién se usa para representar identificadores que son de 32 bits independientemente de la arquitectura (aunque Sizetodavía dice 8 en ese caso). La especificación de CLI solo señala que es un número entero que es de "tamaño nativo", pero eso no dice mucho, en realidad.
Luaan

@Luaan que realmente no cambia nada en mi respuesta, ¿verdad? IntPtr se llama (y se usa en toda la fuente CLR) como un valor lo suficientemente grande como para contener una dirección de memoria. Puede contener valores más pequeños, por supuesto. Algunas arquitecturas tienen varios tipos de puntero, pero deben tener uno que sea el más grande del conjunto.
Daniel Earwicker

@DanielEarwicker Bueno, no es un problema con ninguna implementación actual de .NET, que yo sepa. Sin embargo, el problema (histórico) no se trata solo del tamaño: los diversos punteros pueden ser completamente incompatibles. En un ejemplo más cercano a hoy, PAE usaría direcciones de 64 bits a pesar de que el "tamaño del puntero nativo" todavía era de 32 bits. Se remonta al argumento "¿qué significa realmente 'sistema de 32 bits'?" Tenemos registros numéricos de 256 bits y 512 bits ahora, pero aún así lo llamamos 64 bits. Aunque en realidad no puede direccionar 64 bits de memoria física con sus "punteros" de 64 bits. Es un desastre.
Luaan

1
Parte de esto es complicado, pero IntPtr sigue siendo "un tipo de valor lo suficientemente grande como para almacenar una dirección de memoria". No es tan grande como el registro de hardware más grande, para tomar uno de sus ejemplos. Eso no es para lo que sirve. Es lo suficientemente grande como para representar una dirección de memoria. Luego hay cosas como esta: stackoverflow.com/questions/12006854/... donde tenemos la palabra "puntero" que se usa para algo que no sea una dirección de memoria, razón por la cual dije específicamente "dirección de memoria".
Daniel Earwicker

48

Aquí hay un ejemplo:

Estoy escribiendo un programa C # que interactúa con una cámara de alta velocidad. La cámara tiene su propio controlador que adquiere imágenes y las carga automáticamente en la memoria de la computadora.

Entonces, cuando estoy listo para traer la última imagen a mi programa para trabajar, el controlador de la cámara me proporciona un IntPtr donde la imagen YA está almacenada en la memoria física, para que no tenga que perder tiempo / recursos creando otro bloque de memoria para almacenar una imagen que ya está en memoria. IntPtr solo me muestra dónde está la imagen.


77
Entonces, ¿el IntPtr simple le permite usar un puntero no administrado (como el que se usa en el controlador de su cámara) en el código administrado?
Callum Rogers

55
Si. Bueno, en este caso, lo más probable es que el controlador de la cámara utilice controladores no administrados debajo del capó, pero para funcionar correctamente en el mundo de solo administración, proporciona IntPtr para que pueda trabajar con los datos de manera segura.
bufferz

3
Entonces, ¿por qué no te devolvería una secuencia (matriz de bytes)? ¿Por qué no es seguro o no puede devolver el valor?
The Muffin Man

35

Una interpretación directa

Un IntPtr es un número entero que tiene el mismo tamaño que un puntero .

Puede usar IntPtr para almacenar un valor de puntero en un tipo sin puntero. Esta característica es importante en .NET ya que el uso de punteros es muy propenso a errores y, por lo tanto, es ilegal en la mayoría de los contextos. Al permitir que el valor del puntero se almacene en un tipo de datos "seguro", la plomería entre segmentos de código inseguro se puede implementar en un código de alto nivel más seguro, o incluso en un lenguaje .NET que no admita directamente punteros.

El tamaño de IntPtr es específico de la plataforma, pero este detalle rara vez necesita ser considerado, ya que el sistema usará automáticamente el tamaño correcto.

El nombre "IntPtr" es confuso, algo así Handlepodría haber sido más apropiado. Mi conjetura inicial fue que "IntPtr" era un puntero a un número entero. La documentación de MSDN de IntPtr entra en detalles algo crípticos sin proporcionar mucha información sobre el significado del nombre.

Una perspectiva alternativa

Un IntPtres un puntero con dos limitaciones:

  1. No se puede desreferenciar directamente
  2. No sabe el tipo de datos a los que apunta.

En otras palabras, un IntPtres como un void*- pero con la característica adicional de que puede (pero no debe) usarse para la aritmética básica del puntero.

Para desreferenciar un IntPtr, puede convertirlo en un puntero verdadero (una operación que solo se puede realizar en contextos "inseguros") o puede pasarlo a una rutina auxiliar como las proporcionadas por la InteropServices.Marshalclase. Usar la Marshalclase da la ilusión de seguridad ya que no requiere que estés en un contexto explícito "inseguro". Sin embargo, no elimina el riesgo de estrellarse que es inherente al uso de punteros.


2
Existe algún precedente para el nombre "intptr" del estándar C99 del lenguaje de programación "C". linux.die.net/man/3/intptr_t .
Brent Bradburn

17

¿Qué es un puntero?

En todos los idiomas, un puntero es un tipo de variable que almacena una dirección de memoria, y puede pedirles que le digan la dirección a la que apuntan o el valor de la dirección a la que apuntan.

Un puntero puede considerarse como una especie de marca de libro. Excepto que, en lugar de usarse para saltar rápidamente a una página de un libro, se usa un puntero para realizar un seguimiento o mapear bloques de memoria.

Imagine la memoria de su programa precisamente como una gran matriz de 65535 bytes.

Los punteros apuntan obedientemente

Los punteros recuerdan una dirección de memoria cada uno y, por lo tanto, cada uno apunta a una única dirección en la memoria.

Como grupo, los punteros recuerdan y recuerdan direcciones de memoria, obedeciendo cada comando hasta la saciedad.

Eres su rey

Punteros en C #

Específicamente en C #, un puntero es una variable entera que almacena una dirección de memoria entre 0 y 65534.

También específicos de C #, los punteros son de tipo int y, por lo tanto, están firmados.

Sin embargo, no puede usar direcciones numeradas negativamente, tampoco puede acceder a una dirección superior a 65534. Cualquier intento de hacerlo arrojará una excepción System.AccessViolationException.

Un puntero llamado MyPointer se declara así:

int * MyPointer;

Un puntero en C # es un int, pero las direcciones de memoria en C # comienzan en 0 y se extienden hasta 65534.

Las cosas puntiagudas deben manejarse con especial cuidado

La palabra inseguro tiene la intención de asustarlo, y por una muy buena razón: los punteros son cosas puntiagudas, y las cosas puntiagudas, por ejemplo, espadas, hachas, punteros, etc., deben manejarse con especial cuidado.

Los punteros le dan al programador un control estricto de un sistema. Por lo tanto, es probable que los errores cometidos tengan consecuencias más graves.

Para usar punteros, el código inseguro debe estar habilitado en las propiedades de su programa, y ​​los punteros deben usarse exclusivamente en métodos o bloques marcados como inseguros.

Ejemplo de un bloque inseguro

unsafe
{
    // Place code carefully and responsibly here.

}

Cómo usar punteros

Cuando las variables u objetos se declaran o instancian, se almacenan en la memoria.

  • Declare un puntero utilizando el prefijo del símbolo *.

int *MyPointer;

  • Para obtener la dirección de una variable, use el prefijo & símbolo.

MyPointer = &MyVariable;

Una vez que se asigna una dirección a un puntero, se aplica lo siguiente:

  • Sin el prefijo * para referirse a la dirección de memoria que se señala como int.

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

  • Con * prefijo para obtener el valor almacenado en la dirección de memoria a la que apunta.

"MyPointer is pointing at " + *MyPointer;

Como un puntero es una variable que contiene una dirección de memoria, esta dirección de memoria se puede almacenar en una variable de puntero.

Ejemplo de punteros utilizados con cuidado y responsabilidad

    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 el tipo del puntero es un int. Esto se debe a que C # interpreta las direcciones de memoria como números enteros (int).

¿Por qué es int en lugar de uint?

No hay una buena razón.

¿Por qué usar punteros?

Los punteros son muy divertidos. Con gran parte de la computadora controlada por la memoria, los punteros le otorgan a un programador mayor control de la memoria de su programa.

Monitoreo de memoria.

Use punteros para leer bloques de memoria y monitorear cómo los valores apuntados cambian con el tiempo.

Cambie estos valores de manera responsable y realice un seguimiento de cómo afectan sus cambios a su computadora.


2
65534parece muy incorrecto como un rango de puntero. Debes proporcionar una referencia.
Brent Bradburn

1
Lo voté porque es un gran artículo que explica los punteros. Me gustaría ver algunas referencias a las especificaciones que ha mencionado (como se comentó anteriormente). Sin embargo; Esta respuesta no tiene nada que ver con la pregunta. La pregunta era sobre System.IntPtr. Me gustaría ver la respuesta actualizada al final explicando qué es también System.IntPtry cómo se relaciona con los punteros inseguros en C #, por favor.
Michael Puckett II

7

MSDN nos dice:

El tipo IntPtr está diseñado para ser un número entero cuyo tamaño es específico de la plataforma. Es decir, se espera que una instancia de este tipo sea de 32 bits en hardware y sistemas operativos de 32 bits, y 64 bits en hardware y sistemas operativos de 64 bits.

El tipo IntPtr puede ser utilizado por idiomas que admiten punteros, y como un medio común para referirse a datos entre idiomas que admiten y no admiten punteros.

Los objetos IntPtr también se pueden usar para contener asas. Por ejemplo, las instancias de IntPtr se usan ampliamente en la clase System.IO.FileStream para contener identificadores de archivos.

El tipo IntPtr es compatible con CLS, mientras que el tipo UIntPtr no. Solo se usa el tipo IntPtr en Common Language Runtime. El tipo UIntPtr se proporciona principalmente para mantener la simetría arquitectónica con el tipo IntPtr.

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


5

Bueno, esta es la página de MSDN que trata IntPtr.

La primera línea dice:

Un tipo específico de plataforma que se utiliza para representar un puntero o un identificador.

En cuanto a qué puntero o identificador es, la página continúa:

El tipo IntPtr puede ser utilizado por idiomas que admiten punteros, y como un medio común para referirse a datos entre idiomas que admiten y no admiten punteros.

Los objetos IntPtr también se pueden usar para contener asas. Por ejemplo, las instancias de IntPtr se usan ampliamente en la clase System.IO.FileStream para contener identificadores de archivos.

Un puntero es una referencia a un área de memoria que contiene algunos datos que le interesan.

Un identificador puede ser un identificador para un objeto y se pasa entre métodos / clases cuando ambos lados necesitan acceder a ese objeto.


2

Un IntPtres un tipo de valor que se utiliza principalmente para contener direcciones de memoria o identificadores. Un puntero es una dirección de memoria. Un puntero se puede escribir (por ejemplo int*) o sin escribir (por ejemplo void*). Un identificador de Windows es un valor que generalmente es del mismo tamaño (o más pequeño) que una dirección de memoria y representa un recurso del sistema (como un archivo o ventana).

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.