web-dev-qa-db-fra.com

Adresse mémoire et variable C #

en C #, existe-t-il un moyen de

  1. Obtenir l'adresse mémoire stockée dans une variable de type référence?
  2. Obtenir l'adresse mémoire d'une variable?

ÉDITER:

int i;
int* pi = &i;
  • Comment imprimer la valeur hexadécimale de pi?
25
Ray Lu

Pour le n ° 2, le & fonctionnera de la même manière qu'en 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 ramasse-miettes ne la déplace pas , bien que.

Pour # 1, les types de référence sont plus compliqués: 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 sous forme de nombre, vous pouvez convertir du type pointeur en IntPtr (un type entier défini pour avoir la même taille qu'un pointeur), et de là en uint ou ulong (selon 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();
    }
}
14
Jeffrey Hantin

Le numéro 1 n'est pas du tout possible, 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à fixée, mais si la variable est membre d'un objet, vous devez épingler cet objet en mémoire à l'aide du mot-clé fixed afin qu'il n'est pas déplacé par le garbage collector.

5
Guffa

Pour répondre le plus correctement à votre question:

# 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 en fait le pointeur interne vers l'objet en mémoire. N'oubliez pas que l'adresse peut changer à tout moment à cause 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);