C # adresse mémoire et variable

En C#, y a-t-il un moyen de

  1. récupère l'adresse mémoire stockée dans un variable de type de référence?
  2. récupère l'adresse mémoire d'un variable?

Modifier:

int i;
int* pi = &i;
  • Comment imprimez-vous la valeur hexadécimale de pi?
21
demandé sur Ray Lu 2009-02-26 05:01:36

3 réponses

Pour #2, l'opérateur & fonctionnera de la même manière que dans C. Si la variable n'est pas sur la pile, vous devrez peut-être utiliser une instruction fixed pour l'épingler pendant que vous travaillez afin que le garbage collector ne la déplace pas.

Pour #1, les types de référence sont plus délicats: vous devrez utiliser un GCHandle, et le type de référence doit être blittable, c'est-à-dire avoir une disposition de mémoire définie et être copiable au niveau du BIT.

Pour accéder à l'adresse en tant que nombre, vous pouvez convertir du type de pointeur à IntPtr (un type entier défini pour avoir la même taille qu'un pointeur), et de là à uint ou ulong (en fonction de la taille du pointeur de la machine sous-jacente).

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();
    }
}
13
répondu Jeffrey Hantin 2009-02-26 22:45:11

Le numéro 1 n'est pas possible du tout, vous ne pouvez pas avoir de pointeur vers un objet géré. Cependant, vous pouvez utiliser une structure IntPtr pour obtenir des informations sur l'adresse du pointeur dans la référence:

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

Pour le numéro 2, vous utilisez l'opérateur&:

int* p = &myIntVariable;

Les pointeurs doivent bien sûr être effectués dans un bloc non sécurisé, et vous devez autoriser le code non sécurisé dans les paramètres du projet. Si la variable est une variable locale dans une méthode, elle est allouée sur la pile, donc elle est déjà la variable est membre d'un objet, vous devez épingler cet objet en mémoire en utilisant le mot-clé fixed afin qu'il ne soit pas déplacé par le garbage collector.

5
répondu Guffa 2009-02-26 03:18:57

Pour répondre À votre question le plus correctement:

#1 est possible mais un peu délicat, et ne devrait être fait que pour des raisons de débogage:

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

Cela fonctionne pour n'importe quel objet et renvoie réellement le pointeur interne vers l'objet en mémoire. Rappelez-vous que l'adresse peut changer à tout moment en raison du GC, qui aime déplacer des objets dans la mémoire.

# 2 Les pointeurs ne sont pas des objets et n'héritent donc pas ToString d'eux. Vous devez lancer le pointeur vers IntPtr comme ceci:

Console.WriteLine((IntPtr)pi);
2
répondu IllidanS4 2015-12-10 16:14:15