Search code examples
c++cmemorymemory-address

Adding 1 to an address result in adding 0xE0 to that address


I encountered a really weird behavior while trying to add an offset to an address which I got with the use of & operator. So when I try to add any number to that address, the result is that adddress plus my number times 0xE0 (224).

Offset 0

Offset 1

Offset 2

These are screenshots of the watch list in Visual Studio. The first row of each screenshot is the access of the address of my object, which is correct. The second row is the same access, but we add the variable offset to it. The third row is just the offset itself.

As you can see, everything is fine on the 1st screenshot. But on the second one, the addition is of 0xE0 (0xE38-0xD58=0x0E0) and not 1 as it should be. And on the last screenshot the addition is of 0x1C0 which is 2*0xE0.

On the 2nd row, I expected to see 0x00000255ef9bed58 in the first screenshot, 0x00000255ef9bed59 in the second one and 0x00000255ef9bed5a in the last one.


Solution

  • To understand this, start by compiling and running the following code (C++, though I've included the C lines as comments if you want to use that language):

    #include <iostream>                 // #include <stdio.h>
    int main() {                        // int main(void) {
        int xyzzy[2];
        int *pXyzzy = &xyzzy[0];
        std::cout << pXyzzy << '\n';    // printf("%p\n", pXyzzy);
        pXyzzy = pXyzzy + 1;
        std::cout << pXyzzy << '\n';    // printf("%p\n", pXyzzy);
        return 0;
    }
    

    The output of that will be something like (with my comments added):

    0x7fffc9ef1150
    0x7fffc9ef1154  // four bytes on
    

    That's a clear difference of four bytes despite the fact that all you did was add one to the address between the two outputs.

    That's because pointer arithmetic is scaled based on the size of the thing you're pointing at. In other words, adding one doesn't add one byte, it adds X bytes where X is (in this case) 4, the size of an int.

    Exactly the same thing is happening in your debugger session since it would be disconcerting (and rather painful to debug) if the compiler and debugger disagreed on how expressions were evaluated). If you were to print out the size of the structure you're adding one to, you will find it is 0xe0 bytes long.

    If you really wanted to add one byte, you need to tell the compiler to treat it as something with a size of one byte, something like:

    pXyzzy = (int*)((char*)pXyzzy + 1);
    

    This results in:

    0x7fffdbd74000
    0x7fffdbd74001 // one byte on