c# - ¿Qué es exactamente un IntPtr?
(7)
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 que no sea puntero. Esta característica es importante en .NET ya que el uso de punteros es altamente propenso a errores y, por lo tanto, 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ódigos inseguros puede implementarse en un código de alto nivel más seguro, o incluso en un lenguaje .NET que no admita los punteros directamente.
El tamaño de IntPtr es específico de la plataforma, pero este detalle rara vez debe tenerse en cuenta, ya que el sistema utilizará automáticamente el tamaño correcto.
El nombre "IntPtr" es confuso, algo así como Handle
podría haber sido más apropiado. Mi suposición inicial fue que "IntPtr" era un puntero a un número entero. La documentación de MSDN de IntPtr entra en detalles un tanto crípticos sin proporcionar mucho conocimiento sobre el significado del nombre.
Una perspectiva alternativa
Un IntPtr
es un puntero con dos limitaciones:
- No puede ser directamente desreferenciado
- No sabe el tipo de datos que apunta.
En otras palabras, un IntPtr
es como un void*
, pero con la función adicional que puede (pero no debería) ser utilizado para la aritmética del puntero básico.
Para desreferenciar un IntPtr
, puede convertirlo en un puntero verdadero (una operación que solo puede realizarse en contextos "inseguros") o puede pasarlo a una rutina de ayuda como las provistas por la clase InteropServices.Marshal
. Usar la clase Marshal
da la ilusión de seguridad ya que no requiere que estés en un contexto "inseguro" explícito. Sin embargo, no elimina el riesgo de bloqueo que es inherente al uso de punteros.
Al usar IntelliSense y mirar el código de otras personas, me encontré con este tipo de IntPtr
; cada vez que ha necesitado ser utilizado, simplemente he puesto null
o IntPtr.Zero
y IntPtr.Zero
encontrado que la mayoría de las funciones funcionan. ¿Qué es exactamente y cuándo / por qué se usa?
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 en donde la imagen YA está almacenada en la memoria física, así que no tengo que perder tiempo / recursos creando otra bloque de memoria para almacenar una imagen que ya está en la memoria. El IntPtr solo me muestra dónde está la imagen.
Bueno, esta es la http://msdn.microsoft.com/en-us/library/system.intptr(VS.71).aspx que trata con IntPtr
.
La primera línea dice:
Un tipo específico de plataforma que se usa para representar un puntero o un manejador.
En cuanto a lo que es un puntero o manejador, la página continúa diciendo:
El tipo IntPtr puede ser utilizado por los lenguajes que admiten punteros, y como un medio común de referirse a los datos entre los lenguajes que admiten punteros o no.
Los objetos IntPtr también se pueden usar para mantener identificadores. Por ejemplo, las instancias de IntPtr se usan ampliamente en la clase System.IO.FileStream para contener identificadores de archivo.
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 ambas partes necesitan acceder a ese objeto.
Es un entero de tamaño "nativo (específico de la plataforma)". Está internamente representado como void*
pero expuesto como un número entero. Puede usarlo siempre que necesite almacenar un puntero no administrado y no desee usar unsafe
código unsafe
. IntPtr.Zero
es efectivamente NULL
(un puntero nulo).
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 directamente utilizable como una dirección de memoria en un código administrado de forma segura.
Puede usar IntPtr.Size
para averiguar si se está ejecutando en un proceso de 32 bits o de 64 bits, ya que será de 4 u 8 bytes respectivamente.
MSDN nos dice:
El tipo IntPtr está diseñado para ser un 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 los lenguajes que admiten punteros, y como un medio común de referirse a los datos entre los lenguajes que admiten punteros o no.
Los objetos IntPtr también se pueden usar para mantener identificadores. Por ejemplo, las instancias de IntPtr se usan ampliamente en la clase System.IO.FileStream para contener identificadores de archivo.
El tipo IntPtr cumple con CLS, mientras que el tipo UIntPtr no lo es. Solo el tipo IntPtr se usa en el tiempo de ejecución de lenguaje común. 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
¿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 en 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 seguir 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 sola dirección en la memoria.
Como grupo, los punteros recuerdan y recuerdan direcciones de memoria, obedeciendo cada comando y cada nausea.
Tú 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 para C #, los punteros son de tipo int y, por lo tanto, están firmados.
Sin embargo, no puede usar direcciones negativamente numeradas, ni puede acceder a una dirección por encima de 65534. Cualquier intento de hacerlo arrojará una 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 cuidado especial adicional
La palabra inseguro tiene la intención de asustarlo, y por una muy buena razón: los indicadores son puntiagudos, 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 serias.
Para utilizar 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 son declarados o instanciados, se almacenan en la memoria.
- Declare un puntero usando el * prefijo del símbolo.
int *MyPointer;
- Para obtener la dirección de una variable, usa el prefijo & symbol.
MyPointer = &MyVariable;
Una vez que se asigna una dirección a un puntero, se aplica lo siguiente:
- Sin * prefijo para hacer referencia a la dirección de memoria que se señala como un 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 se 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 usados 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. Dado que gran parte de la computadora está controlada por la memoria, los punteros le dan al programador más control sobre la memoria de su programa.
Monitoreo de la 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 los cambios afectan su computadora.