C # адрес памяти и переменная - PullRequest
24 голосов
/ 26 февраля 2009

в C #, есть ли способ

  1. Получить адрес памяти, сохраненный в переменная ссылочного типа?
  2. Получить адрес памяти переменная

EDIT:

int i;
int* pi = &i;
  • Как вы распечатываете шестнадцатеричное значение числа пи?

Ответы [ 3 ]

14 голосов
/ 26 февраля 2009

Для # 2 оператор & будет работать так же, как и в C. Если переменная не находится в стеке, вам может потребоваться использовать оператор fixed, чтобы зафиксировать ее во время работы, чтобы однако сборщик мусора не перемещает его.

Для # 1 ссылочные типы сложнее: вам нужно будет использовать GCHandle, а ссылочный тип должен быть кратковременным, то есть иметь определенный макет памяти и быть побитовым для копирования.

Чтобы получить доступ к адресу в виде числа, вы можете преобразовать тип указателя в IntPtr (целочисленный тип, определенный по размеру как указатель), а оттуда в uint или ulong ( в зависимости от размера указателя базовой машины).

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();
    }
}
5 голосов
/ 26 февраля 2009

Номер 1 вообще невозможен, у вас не может быть указателя на управляемый объект. Однако вы можете использовать структуру IntPtr для получения информации об адресе указателя в ссылке:

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

Для номера 2 вы используете оператор &:

int* p = &myIntVariable;

Конечно, указатели должны быть сделаны в небезопасном блоке, и вы должны разрешить небезопасный код в настройках проекта. Если переменная является локальной переменной в методе, она размещена в стеке, поэтому она уже исправлена, но если переменная является членом объекта, вы должны закрепить этот объект в памяти, используя ключевое слово fixed, чтобы оно перемещенный сборщиком мусора.

3 голосов
/ 10 декабря 2015

Чтобы ответить на ваш вопрос наиболее правильно:

# 1 возможно, но немного сложно, и должно быть сделано только по причинам отладки:

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

Это работает для любого объекта и фактически возвращает внутренний указатель на объект в памяти. Помните, что адрес может измениться в любой момент из-за GC, который любит перемещать объекты по памяти.

# 2 Указатели не являются объектами и, следовательно, не наследуют ToString от них. Вы должны привести указатель к IntPtr примерно так:

Console.WriteLine((IntPtr)pi);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...