0

i have the following question:

For example, when I have the structure

    IMAGE_SECTION_HEADER STRUCT         |   C1    |    C2      
    Name1                     BYTE      |   +0    |    +0
    union Misc                          |
        PhysicalAddress       DWORD     |    2    |     2
        VirtualSize           DWORD     |    6    |
    ends                                |
    VirtualAddress            DWORD     |    10   |     6
    SizeOfRawData             DWORD     |    14   |     10
    PointerToRawData          DWORD     |    18   |     14
       ...(etc.)

Then how I must count the offsets? The columns C1 and C2 represent my solutions but i am not sure which of the two is right or if both are wrong. Do I have to consider the union in the structure as 1 field, or do I need to consider its fields separately?

best regards,

1 Answer 1

3

A union is a list of fields starting at the same address in memory (except for bitfields, of course). Its size is at least the size of the largest field in it. In your case, it would be 4 bytes.

Note that, like structs, the size can be bigger due to alignment requirements. For example, take this C union:

union MyUnion {
    char a[5];
    int b;
};

The a fields is 5 bytes, b is 4. You would expect the union to be 5 bytes, but, as you can check with sizeof(union MyUnion), it is actually 8. This is because ints are aligned to a 4-byte boundary. Similiarly, shorts are aligned to 2 bytes and doubles to 8. Try it on CodingGround.

You may be asking yourself: why does the compiler align the union size? Isn't aligning the starting address enough? It could well keep the size of MyUnion to 5 and align the start to a 4-byte boundary for the int. The problem comes when you have an array of the union. An array needs to be a contiguous block of memory because of how array and pointer arithmetic works. Given a generic T array[] you have that array[i] == *(array + i) == *((T *) (((char *) array) + i * sizeof(T))). In the example case, MyUnion has a 4-byte alignment requirement (the largest aligment in the union). If you have a MyUnion array[], the starting address will be 4-byte aligned because of the int. This means that array[0] will be correctly aligned. But if the size of the union is 5, then array[1] will be at a 5 bytes offset from the starting address. This is not 4-byte aligned! Aligning the union size to 8 bytes puts array[1] to a 8 bytes offset, which is 4-bytes aligned. Aligning the size by padding the union allows the array to be contiguous while keeping everything aligned.

Bottom line:

In a union (or a struct), both the starting address and the size are aligned to the biggest alignment requirement of the fields.

Of course, alignment requirements may vary between compilers and architectures. Keep that in mind.

Neither C1 nor C2 is correct as far as I can see, since the first field is a byte and not two:

IMAGE_SECTION_HEADER STRUCT         |w/o align| aligned |
Name1                     BYTE      |   +0    |   +0    |
union Misc                          |   +1    |   +4    |
    PhysicalAddress       DWORD     |         |         |
    VirtualSize           DWORD     |         |         |            
ends                                |         |         |
VirtualAddress            DWORD     |   +5    |   +8    |
SizeOfRawData             DWORD     |   +9    |   +12   |
PointerToRawData          DWORD     |   +13   |   +16   |
   ...(etc.)
1
  • 1
    Reading the answer again I realized I wasn't very clear. The int alignment is making the size 8 bytes. This has to do with arrays. I updated the answer, please check it. I also updated the CodingGound sample to show alignment. May 13, 2015 at 7:29

Not the answer you're looking for? Browse other questions tagged or ask your own question.