IBM Z and LinuxONE - Languages

Languages

Languages

Broad range of supported development languages and tools allows to transform software delivery practices.

 View Only

A visual example of #pragma pack

By FANG LU posted Tue March 24, 2020 07:39 PM

  
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. 
0 comments
2 views

Permalink