C# memory address and variable

62,740

Solution 1

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

Solution 2

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.

Solution 3

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);
Share:
62,740

Related videos on Youtube

Ray Lu
Author by

Ray Lu

...AI & Blockchain...

Updated on July 09, 2022

Comments

  • Ray Lu
    Ray Lu almost 2 years

    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?
  • Ray Lu
    Ray Lu about 15 years
    #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?
  • Ray Lu
    Ray Lu about 15 years
    Weired, why code can not compile with string str = "hello"; string* ptr = str; ? any idea?
  • Guffa
    Guffa about 15 years
    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.
  • xpp_T
    xpp_T about 15 years
    Console.WriteLine("0x" + pi.ToString("x") would print the hex value
  • Ray Lu
    Ray Lu about 15 years
    @Hamish, pi.ToString("x") raise compilation error. "Operator '.' cannot be applied to operand of type 'int*'"
  • Guffa
    Guffa over 14 years
    Why the downvote? If you don't say what it is that you don't like, it's rather pointless...
  • rism
    rism about 9 years
    You need to use the "->" operator. pi->ToString()
  • Jeffrey Hantin
    Jeffrey Hantin about 9 years
    @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.
  • Antosha
    Antosha over 7 years
    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.