в С#, есть ли способ
- Получить адрес памяти, хранящийся в переменная ссылочного типа?
- Получить адрес памяти переменная?
EDIT:
int i;
int* pi = &i;
- Как вы распечатываете шестнадцатеричное значение pi?
в С#, есть ли способ
EDIT:
int i;
int* pi = &i;
Для # 2 оператор &
будет работать так же, как и в C. Если переменная не находится в стеке, вам может потребоваться использовать оператор fixed
, чтобы выровнять его во время работы, чтобы однако сборщик мусора не перемещает его.
Для # 1 ссылочные типы сложнее: вам нужно использовать GCHandle
, а ссылочный тип должен быть blittable, т.е. иметь определенный макет памяти и быть побитовым.
Чтобы получить доступ к адресу в виде номера, вы можете использовать тип указателя для 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 вообще невозможен, вы не можете иметь указатель на управляемый объект. Тем не менее, вы можете использовать структуру IntPtr для получения информации об адресе указателя в ссылке:
GCHandle handle = GCHandle.Alloc(str, GCHandleType.Pinned);
IntPtr pointer = GCHandle.ToIntPtr(handle);
string pointerDisplay = pointer.ToString();
handle.Free();
Для номера 2 вы используете оператор and:
int* p = &myIntVariable;
Указатели, конечно, должны выполняться в небезопасном блоке, и вы должны разрешить небезопасный код в настройках проекта. Если переменная является локальной переменной в методе, она выделяется в стеке, поэтому она уже исправлена, но если переменная является членом объекта, вы должны привязать этот объект в памяти с помощью ключевого слова fixed
, чтобы он не перемещается сборщиком мусора.
Чтобы ответить на ваш вопрос наиболее правильно:
# 1 возможно, но немного сложнее, и его нужно делать только для отладки:
object o = new object();
TypedReference tr = __makeref(o);
IntPtr ptr = **(IntPtr**)(&tr);
Это работает для любого объекта и фактически возвращает внутренний указатель на объект в памяти. Помните, что адрес может измениться в любой момент из-за GC, которому нравится перемещать объекты по всей памяти.
# 2 Указатели не являются объектами и, следовательно, не наследуют ToString от них. Вы должны направить указатель на IntPtr так:
Console.WriteLine((IntPtr)pi);