views:

367

answers:

3
+1  Q: 

IntPtr addition

So from what I can tell, every managed example of IntPtr addition I have found is WRONG.

For example: http://www.atalasoft.com/cs/blogs/stevehawley/archive/2006/10/16/10987.aspx

My thought being, that if IntPtr is at (or near) int32.MaxValue on a 32-bit system, and you add an offset which overflows int32, isn't that still a valid memory address (as it would be valid in uint32, and would be represented by a negative number in IntPtr)?!

I believe the code should be something like:

public static IntPtr Offset(IntPtr src, int offset)
{
    switch (IntPtr.Size) {
    case 4:
        return new IntPtr((int)((uint)src + offset));
    case 8:
        return new IntPtr((long)((ulong)src + offset));
    default:
        throw new NotSupportedException("Not supported");
    }
}

Am I crazy?

Does anyone have a tried and true IntPtr addition example?

A: 

Before addition, the IntPtr is cast to a uint, then the offset is applied. This will work correctly, but the result is a long.

As far as I know, addition of ulong and an int is not possible, so the 64-bit pointer part is incorrect. Indeed it doesn't even compile. I can't really think of an elegant solution, but just using a long instead would probably be safe. That's half of a sh*tload of memory you could use*, 8 exabytes :) Memory address mapping could theoretically be a problem there though.

*: well, if the current .NET Framework implementation wouldn't stop you from doing so long before that of course :)

Thorarin
+1  A: 

I think the point is that if you overflow an int, you still get the appropriate value. Try this:

//-2147483645
Console.WriteLine( int.MaxValue + 4 );

//2147483651
Console.WriteLine( (uint)(int.MaxValue + 4) );

Given that int.MaxValue is 2147483647, casting the overflowed negative number to uint does in fact give the right value.

Ant
Stupidly, I hadn't tried this until now (and you have to add unchecked{} around it for it to compile), but you appear to be correct. I thought for sure that .NET would throw an error but it doesn't
userx
Little research shows that as long as "unchecked" is used here, this approach works just fine:http://msdn.microsoft.com/en-us/library/khy08726%28VS.80%29.aspx
userx
Ah yes - I forgot about unchecked. I seem to remember that for release builds the default is unchecked anyway - although if the compiler can tell something will overflow (like my example!! doh!) then it'll stop you.
Ant
A: 

.NET 4.0 adds a new static method IntPtr.Add(IntPtr pointer, int offset).

On earlier .NET versions, an alternative method to converting to an integer is to use an 'unsafe' code block and cast the IntPtr to a (byte *). Perform your addition and turn the result back into an IntPtr. The compiler takes care of pointer width details. :-)

Example:

  new IntPtr((byte *)pipe.Root + EventNameOffset)

or:

  (IntPtr)((byte *)pipe.Root + EventNameOffset)
Jonathan Gilbert