2009-02-26 45 views
20

en C#, ¿hay una manera deC# dirección de memoria y las variables

  1. Obtener la dirección de memoria almacenada en una variable de tipo referencia?
  2. Obtiene la dirección de memoria de una variable ?

EDIT:

int i; 
int* pi = &i; 
  • ¿Cómo imprimir el valor hexadecimal de pi?

Respuesta

13

Para # 2, el operador & funcionará de la misma manera como en C. Si la variable no está en la pila, puede que tenga que utilizar una declaración fixed a la clavija hacia abajo mientras se trabaja por lo que la basura el coleccionista no lo mueve, sin embargo.

Para el n. ° 1, los tipos de referencia son más complicados: necesitará un GCHandle, y el tipo de referencia debe ser blittable, es decir, tener un diseño de memoria definido y ser copiable por bit.

Con el fin de acceder a la dirección como un número, puede convertir de un tipo de puntero a IntPtr (un tipo entero definido para ser el mismo tamaño que un puntero), y de allí a uint o ulong (dependiendo del tamaño del puntero de la máquina subyacente).

using System; 
using System.Runtime.InteropServices; 

[StructLayout(LayoutKind.Sequential)] 
class Blittable 
{ 
    int x; 
} 

class Program 
{ 
    public static unsafe void Main() 
    { 
     int i; 
     object o = new Blittable(); 
     int* ptr = &i; 
     IntPtr addr = (IntPtr)ptr; 

     Console.WriteLine(addr.ToString("x")); 

     GCHandle h = GCHandle.Alloc(o, GCHandleType.Pinned); 
     addr = h.AddrOfPinnedObject(); 
     Console.WriteLine(addr.ToString("x")); 

     h.Free(); 
    } 
} 
+1

# 2, que es fresco. pero ¿cómo puedes obtener la dirección de la memoria como una cadena? di int i; int * pi = & i; No puedo imprimirlo usando la consola.WriteLine (pi); Espero que se imprima algo como 0x0439ecc4. ¿Cualquier pista? –

+0

Console.WriteLine ("0x" + pi.ToString ("x") imprimiría el valor hexadecimal –

+0

@Hamish, pi.ToString ("x") aumenta el error de compilación. "Operator '.' No se puede aplicar al operando de tipo 'int *' " –

5

El número 1 no es posible en absoluto, no puede tener un puntero a un objeto administrado. Sin embargo, se puede utilizar una estructura IntPtr para obtener información acerca de la dirección del puntero en la referencia:

GCHandle handle = GCHandle.Alloc(str, GCHandleType.Pinned); 
IntPtr pointer = GCHandle.ToIntPtr(handle); 
string pointerDisplay = pointer.ToString(); 
handle.Free(); 

Para el número 2 se utiliza el & operador:

int* p = &myIntVariable; 

punteros, por supuesto, tienen que ser hecho en un bloque inseguro, y debe permitir código no seguro en la configuración del proyecto. Si la variable es una variable local en un método, está asignada en la pila, por lo que ya está fija, pero si la variable es miembro de un objeto, debe anclar ese objeto en la memoria utilizando la palabra clave fixed para que no se mueva. el recolector de basura.

+0

Weired, por qué el código no puede compilarse con str cadena =" hola "; cadena * ptr = str;? alguna idea? –

+0

Es malo, eso en realidad no es posible en absoluto. no puede tener un puntero a un objeto administrado, tiene que usar un IntPtr. – Guffa

+5

¿Por qué el downvote? Si no dice qué es lo que no le gusta, es bastante inútil ... – Guffa

2

Para responder a su pregunta más correcta:

# 1 es posible, pero un poco complicado, y se debe hacer solamente por razones de depuración:

object o = new object(); 
TypedReference tr = __makeref(o); 
IntPtr ptr = **(IntPtr**)(&tr); 

Esto funciona para cualquier objeto y, de hecho devuelve el interior puntero al objeto en la memoria. Recuerde que la dirección puede cambiar en cualquier momento debido al GC, que le gusta mover objetos a través de la memoria.

# 2 Los punteros no son objetos y, por lo tanto, no heredan ToString de ellos. Usted tiene que emitir el puntero a IntPtr así:

Console.WriteLine((IntPtr)pi); 
Cuestiones relacionadas