Here's a quick visual demonstration of the #pragma pack functionality. Test case:
// $ xlc pack.c -q64 -g -qdfp
// using -qdfp for _Decimal128 support
#include <stdio.h>
//#pragma pack(1) // ** Modify this value **
struct test {
char aa; // size = 1
int bb; // size = 4
short cc; // size = 2
long dd; // size = 8 (compiled in 64-bit mode)
union { // size = 16 (_Decimal128 is 16, using union to set the value)
_Decimal128 ee1;
long ee2[2];
} ee;
};
int main()
{
struct test a;
a.aa=(char)0x44;
a.bb=0x55555555;
a.cc=0x6666;
a.dd=0x7777777777777777;
a.ee.ee2[0]=0x8888888888888888;
a.ee.ee2[1]=0x8888888888888888;
int ptr=0xffffffff;
printf("size of struct = %d\n",sizeof(struct test));
printf("a =%p\n",&a);
printf("aa=%p offset = %d\n",&(a.aa),(int)(&(a.aa))-(int)(&a));
printf("bb=%p offset = %d\n",&(a.bb),(int)(&(a.bb))-(int)(&a));
printf("cc=%p offset = %d\n",&(a.cc),(int)(&(a.cc))-(int)(&a));
printf("dd=%p offset = %d\n",&(a.dd),(int)(&(a.dd))-(int)(&a));
printf("ee=%p offset = %d\n",&(a.ee),(int)(&(a.ee))-(int)(&a));
printf("pt=%p\n",&ptr);
}
By default, the natural alignments of datatypes in the struct are used, i.e. if the size of the datatype is a multiple of the memory address. This can cause gaps in the struct in memory, making it larger than expected:
size of struct = 48
a =fffffffffffe5f0
aa=fffffffffffe5f0 offset = 0
bb=fffffffffffe5f4 offset = 4
cc=fffffffffffe5f8 offset = 8
dd=fffffffffffe600 offset = 16
ee=fffffffffffe610 offset = 32
pt=fffffffffffe620
0x0fffffffffffe5f0: 44dc0ffe 55555555 66660ffe e0ddf00d
0x0fffffffffffe600: 77777777 77777777 badc0ffe e0ddf00d
0x0fffffffffffe610: 88888888 88888888 88888888 88888888
0x0fffffffffffe620: ffffffff e0ddf00d badc0ffe e0ddf00d
The #pragma pack option allows you to change the alignment of datatypes within a struct to align to boundaries smaller than it's size. It does not force alignment of ALL variables - it only changes the alignment of variables larger than the pack setting. For example, if we set the #pragma pack to '8', the 16-byte _Decimal128 datatype aligns on the 8-byte boundary, but the other datatypes still use their natural alignment (note that the size of the struct has decreased):
#pragma pack(8)
size of struct = 40
a =fffffffffffe5f0
aa=fffffffffffe5f0 offset = 0
bb=fffffffffffe5f4 offset = 4
cc=fffffffffffe5f8 offset = 8
dd=fffffffffffe600 offset = 16
ee=fffffffffffe608 offset = 24
pt=fffffffffffe618
0x0fffffffffffe5f0: 44dc0ffe 55555555 66660ffe e0ddf00d
0x0fffffffffffe600: 77777777 77777777 88888888 88888888
0x0fffffffffffe610: 88888888 88888888 ffffffff e0ddf00d
How about if we change the pack setting to 4? Now both the 64-bit long variable and the _Decimal128 variable have changed alignment:
#pragma pack(4)
size of struct = 36
a =fffffffffffe600
aa=fffffffffffe600 offset = 0
bb=fffffffffffe604 offset = 4
cc=fffffffffffe608 offset = 8
dd=fffffffffffe60c offset = 12
ee=fffffffffffe614 offset = 20
pt=fffffffffffe624
0x0fffffffffffe600: 44dc0ffe 55555555 66660ffe 77777777
0x0fffffffffffe610: 77777777 88888888 88888888 88888888
0x0fffffffffffe620: 88888888 ffffffff badc0ffe e0ddf00d
Continuing on to pack setting of 2:
#pragma pack(2)
size of struct = 32
a =fffffffffffe600
aa=fffffffffffe600 offset = 0
bb=fffffffffffe602 offset = 2
cc=fffffffffffe606 offset = 6
dd=fffffffffffe608 offset = 8
ee=fffffffffffe610 offset = 16
pt=fffffffffffe620
0x0fffffffffffe600: 44dc5555 55556666 77777777 77777777
0x0fffffffffffe610: 88888888 88888888 88888888 88888888
0x0fffffffffffe620: ffffffff e0ddf00d badc0ffe e0ddf00d
and 1:
#pragma pack(1)
size of struct = 31
a =fffffffffffe600
aa=fffffffffffe600 offset = 0
bb=fffffffffffe601 offset = 1
cc=fffffffffffe605 offset = 5
dd=fffffffffffe607 offset = 7
ee=fffffffffffe60f offset = 15
pt=fffffffffffe620
0x0fffffffffffe600: 44555555 55666677 77777777 77777788
0x0fffffffffffe610: 88888888 88888888 88888888 8888880d
0x0fffffffffffe620: ffffffff e0ddf00d badc0ffe e0ddf00d
At this point there are no more padding bytes, and the struct is as small as possible: 1+4+2+8+16 = 31 bytes . Notice, though, that the 'ptr' integer variable defined after 'struct test a' is aligned on the 4-byte boundary, leaving an extra byte.