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 int
s are aligned to a 4-byte boundary. Similiarly, short
s are aligned to 2 bytes and double
s 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.)