views:

4776

answers:

2

in C#, is there a way to

  1. Get the memory address stored in a reference type variable?
  2. Get the memory address of a variable?

EDIT:

int i;
int* pi = &i;
  • How do you print out the hex value of pi?
+4  A: 

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();
    }
}
Jeffrey Hantin
#2, that is cool. but how can you get the memory address as a string. say int i; int* pi = I cannot print it using Console.WriteLine(pi);I expect something like 0x0439ecc4 to be printed. Any clue?
codemeit
Console.WriteLine("0x" + pi.ToString("x") would print the hex value
Hamish Smith
@Hamish, pi.ToString("x") raise compilation error. "Operator '.' cannot be applied to operand of type 'int*'"
codemeit
A: 

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.

Guffa
Weired, why code can not compile with string str = "hello"; string* ptr = str; ? any idea?
codemeit
My bad, that is actually not possible at all. You can't have a pointer to a managed object, you have to use an IntPtr.
Guffa
Why the downvote? If you don't say what it is that you don't like, it's rather pointless...
Guffa