C# memory address and variable
in C#, is there a way to
- Get the memory address stored in a reference type variable?
- Get the memory address of a variable?
EDIT:
int i;
int* pi = &i;
- How do you print out the hex value of pi?
For #2, the &
operator will work in the same fashion as in C. If the variable is not on the stack, you may need to use a fixed
statement to pin it down while you work so the garbage collector does not move it, though.
For #1, reference types are trickier: you'll need to use a GCHandle
, and the reference type has to be blittable, i.e. have a defined memory layout and be bitwise copyable.
In order to access the address as a number, you can cast from pointer type to IntPtr
(an integer type defined to be the same size as a pointer), and from there to uint
or ulong
(depending on the pointer size of the underlying machine).
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();
}
}
Number 1 is not possible at all, you can't have a pointer to a managed object. However, you can use an IntPtr structure to get information about the address of the pointer in the reference:
GCHandle handle = GCHandle.Alloc(str, GCHandleType.Pinned);
IntPtr pointer = GCHandle.ToIntPtr(handle);
string pointerDisplay = pointer.ToString();
handle.Free();
For number 2 you use the & operator:
int* p = &myIntVariable;
Pointers of course have to be done in a unsafe block, and you have to allow unsafe code in the project settings. If the variable is a local variable in a method, it's allocated on the stack so it's already fixed, but if the variable is a member of an object, you have to pin that object in memory using the fixed
keyword so that it's not moved by the garbage collector.
To answer your question most correctly:
#1 is possible but a bit tricky, and should be only done for debugging reasons:
object o = new object();
TypedReference tr = __makeref(o);
IntPtr ptr = **(IntPtr**)(&tr);
This works for any object and actually returns the internal pointer to the object in memory. Remember the address can change at any moment because of the GC, which likes to move objects across the memory.
#2 Pointers aren't objects and thus don't inherit ToString from them. You have to cast the pointer to IntPtr like so:
Console.WriteLine((IntPtr)pi);