Elliot
Elliot

Reputation: 2033

Pointer arithmetic confusion or weird behavior

When the following has run, I get _pfloatPos and _charPos being different:

    float* const _pData = new float[0x50000000];

    float*  const _floatPos = _pData + 0x400000B0;
    char*   const _charPos = ((char*)_pData) + 0x400000B0 * 4;

    if ((char*)_floatPos !=  _charPos)
    {
        throw "Derp.";
    }

Maybe I've got brain fog and missed something basic. The two addresses should be the same, right?

I looked at the disassembly. 1000002C0h is 4 * 0x400000B0 . For the second one it seems to have been truncated at some point.

        float*  const _floatPos = _pData + 0x400000B0;
00007FF7CE48F6E2  mov         rax,1000002C0h  
00007FF7CE48F6EC  mov         rcx,qword ptr [_pData]  
00007FF7CE48F6F0  add         rcx,rax  
00007FF7CE48F6F3  mov         rax,rcx  
00007FF7CE48F6F6  mov         qword ptr [_floatPos],rax  
        char*   const _charPos = ((char*)_pData) + 0x400000B0 * 4;
00007FF7CE48F6FA  mov         rax,qword ptr [_pData]  
00007FF7CE48F6FE  add         rax,2C0h  
00007FF7CE48F704  mov         qword ptr [_charPos],rax  

I am using visual Studio 2017 Version 15.9.2, but I'm not sure about the version of the compiler.

Upvotes: 0

Views: 158

Answers (2)

Elliot
Elliot

Reputation: 2033

The two integer literals 0x400000B0 and 4 are each only given 4 bytes (even in x86-64), and so multiplying them causes an overflow. Appending L's doesn't change anything. Appending LL's makes them 64-bit, and solves the problem. But my solution will be to use std::int64_t for ints from now on.


Test:

#include <iostream>
#include <cassert>
using namespace std;

int main()
{
    { // plain literals
        float* const _pData = 0;
        float* const _floatPos = _pData + 0x400000B0;
        char* const _charPos = ((char*)_pData) + 0x400000B0 * 4;

        assert((char*)_floatPos != _charPos);
    }

    { // append L
        float* const _pData = 0;
        float* const _floatPos = _pData + 0x400000B0L;
        char* const _charPos = ((char*)_pData) + 0x400000B0L * 4L;

        assert((char*)_floatPos != _charPos);
    } 

    { // append LL
        float* const _pData = 0;
        float* const _floatPos = _pData + 0x400000B0L;
        char* const _charPos = ((char*)_pData) + 0x400000B0LL * 4LL;

        assert((char*)_floatPos == _charPos); // success
    }
}

Upvotes: 1

David Schwartz
David Schwartz

Reputation: 182893

You need 0x400000B0 * 4L or the multiplication will overflow.

Upvotes: 1

Related Questions