2009-02-26 14 views
20

in C#, c'è un modo perC e variabile

  1. Indirizzo memorizzato in una variabile di tipo di riferimento?
  2. Ottieni l'indirizzo di memoria di una variabile ?

EDIT:

int i; 
int* pi = &i; 
  • Come si fa a stampare il valore esadecimale di pi greco?

risposta

13

Per 2 #, l'operatore & funzionerà nello stesso modo come in C. Se la variabile non è in pila, potrebbe essere necessario utilizzare un'istruzione fixed al pin giù mentre si lavora così la spazzatura il collezionista non lo muove, però.

Per il numero 1, i tipi di riferimento sono più complicati: è necessario utilizzare uno GCHandle e il tipo di riferimento deve essere blittabile, ovvero avere un layout di memoria definito ed essere copiabile per bit.

Per poter accedere l'indirizzo come un numero, è possibile trasmettere da tipo puntatore a IntPtr (un tipo intero definito come la stessa dimensione come un puntatore), e da lì a uint o ulong (a seconda della dimensione del puntatore della macchina sottostante).

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, che è cool. ma come si può ottenere l'indirizzo di memoria come una stringa. dì int i; int * pi = & i; Non riesco a stamparlo usando la Console.WriteLine (PI); Mi aspetto che qualcosa come 0x0439ecc4 sia stampato. Qualche indizio? –

+0

Console.WriteLine ("0x" + pi.ToString ("x") stampa il valore esadecimale –

+0

@Hamish, pi.ToString ("x") genera errore di compilazione. "Operatore '.' Non può essere applicato all'operando di tipo 'int *' " –

5

Il numero 1 non è possibile, non è possibile avere un puntatore a un oggetto gestito. Tuttavia, è possibile utilizzare una struttura IntPtr per ottenere informazioni circa l'indirizzo del puntatore nel riferimento:

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

Per il numero 2 si utilizza il & dell'operatore:

int* p = &myIntVariable; 

Puntatori ovviamente devono essere fatto in un blocco non sicuro, e devi consentire il codice non sicuro nelle impostazioni del progetto. Se la variabile è una variabile locale in un metodo, viene allocata nello stack in modo che sia già fissa, ma se la variabile è un membro di un oggetto, devi mettere quell'oggetto in memoria usando la parola chiave fixed in modo che non venga spostato da il netturbino.

+0

Weired, perché il codice non può essere compilato con string str =" hello "; string * ptr = str;? qualsiasi idea? –

+0

Il mio male, che in realtà non è possibile a tutti. non può avere un puntatore a un oggetto gestito, devi usare un IntPtr. – Guffa

+5

Perché il downvote? Se non dici quello che non ti piace, è piuttosto inutile ... – Guffa

2

Per rispondere alla tua domanda più correttamente:

# 1 è possibile, ma un po 'complicato, e dovrebbe essere fatto solo per motivi di debug:

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

Questo funziona per qualsiasi oggetto e in realtà restituisce l'interno puntatore all'oggetto in memoria. Ricorda che l'indirizzo può cambiare in qualsiasi momento a causa del GC, che ama spostare gli oggetti attraverso la memoria.

# 2 I puntatori non sono oggetti e pertanto non ereditano da ToString. Bisogna lanciare il puntatore IntPtr in questo modo:

Console.WriteLine((IntPtr)pi);