Ответов (3)3
Для №2 &
оператор будет работать так же, как и в C. Если переменная отсутствует в стеке, вам может потребоваться использовать fixed
оператор, чтобы закрепить ее во время работы, чтобы сборщик мусора не перемещал ее.
Для №1 ссылочные типы сложнее: вам нужно использовать a 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();
}
}
Чтобы наиболее правильно ответить на ваш вопрос:
№1 возможен, но немного сложен и должен выполняться только в целях отладки:
object o = new object();
TypedReference tr = __makeref(o);
IntPtr ptr = **(IntPtr**)(&tr);
Это работает для любого объекта и фактически возвращает внутренний указатель на объект в памяти. Помните, что адрес может измениться в любой момент из-за GC, который любит перемещать объекты по памяти.
# 2 Указатели не являются объектами и, следовательно, не наследуют от них ToString . Вы должны указать указатель на IntPtr следующим образом:
Console.WriteLine((IntPtr)pi);
Номер 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
ключевого слова, чтобы он не перемещался уборщик мусора.