Search code examples
c++structmemory-alignment

How does everything work (including operator '->'), when sizeof's size and the actual object size don't match?


In the following code I define a structure header of 9 bytes and it's alligned to the size of 16 bytes. Then I dynamically allocate 9 bytes from heap and assign it to the header pointer.

struct header                 
{
     uint8_t chunk_id;               
     long int format;                 
};

int main()
{   
    std::cout << "sizeof(header) " << sizeof(header) << '\n';

    auto head = (header*)malloc(9);
    head->chunk_id =3;
    head->format=5;    
    std::cout << (int)head->chunk_id << " " << head->format << '\n' << sizeof(*head);

    free(head);
    return 0;
}

Output:

sizeof(header) 16
3 5
16

As it turns out, sizeof still informs that this object is 16 bytes (it's 9 though). I guess it just looks at struct's definition. But how does everything work (including operator '->'), when sizeof's size and the actual object size don't match?


Solution

  • But how does everything work (including operator '->'), when sizeof's size and the actual object size don't match?

    Simple: it doesn't. You lied to the implementation, and you therefore invoked undefined behavior.

    First, you never created a header object in the memory; you simply cast a piece of memory into that header object. So you have a pointer that doesn't point to an object, but you pretend that it does.

    Second, even if you tried to create a header object in that memory properly (or alternatively you're using C++20's implicit creation rules), malloc's definition does not require it to return sufficient space to hold more than the number of bytes you specified. Since sizeof(header) is 16, and you only asked for 9, then your code would only work under malloc implementations that will make available 16 or more bytes to your code when you ask for 9 (this is not uncommon, actually). Otherwise, you're creating an object that takes up more memory than is available through that pointer, which is also UB.

    Getting away with something isn't the same thing as "working".