27

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 Answers 4

17

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();
    }
}
Sign up to request clarification or add additional context in comments.

5 Comments

#2, that is cool. but how can you get the memory address as a string. say int i; int* pi = &i; I cannot print it using Console.WriteLine(pi); I expect something like 0x0439ecc4 to be printed. Any clue?
Console.WriteLine("0x" + pi.ToString("x") would print the hex value
@Hamish, pi.ToString("x") raise compilation error. "Operator '.' cannot be applied to operand of type 'int*'"
You need to use the "->" operator. pi->ToString()
@rism, the OP wants the value of the pointer reinterpreted as an integer, not the value pointed to by the pointer. Casting int* to IntPtr allows it.
5

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.

3 Comments

Weired, why code can not compile with string str = "hello"; string* ptr = str; ? any idea?
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.
GCHandle.ToIntPtr returns an internal representation of the handle itself, not the address of the object it points to. If you create multiple handles for the same object, GCHandle.ToIntPtr will return different results for each handle. It is GCHandle.AddrOfPinnedObject that returns the address of the object the handle points to. Please see GCHandle.ToIntPtr vs. GCHandle.AddrOfPinnedObject for more details.
5

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);

Comments

1

Simple answer

static void Main(string[] args)
    {
        unsafe
        {
            int a = 10; 
            int b = 20; 
            int* aPtr = &a;
            int* bPtr = &b;
    
            Console.WriteLine($"Address of a: {(int)aPtr}");
            Console.WriteLine($"Address of b: {(int)bPtr}");
        }
        Console.Read();
    }

Detailed explanation can find here Link: https://youtu.be/OPzUnlDBB_I?feature=shared

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.