Talk about byte alignment in C language pragma pack of n 2

  • 2020-05-12 02:55:54
  • OfStack

#pragma pack(n)

This is the parameter setting for the compiler, about struct byte alignment, #pragma pack specifies how data is aligned in memory.

#pragma pack (n) effect: the C compiler aligns n bytes.
#pragma pack () disables custom byte alignment.


#pragma pack (push,1) action: means to set the original alignment to the stack, and set the new alignment to 1 byte alignment

#pragma pack(pop) action: restore alignment

As you can see, the addition of push and pop restores the alignment to its original state, rather than the compiler default, which is arguably better, but in many cases the difference is small

Such as:

#pragma pack(push) // save alignment

#pragma pack(4)// is set to 4 byte alignment

This is equal to #pragma pack (push,4)

Explanation 1:

Each platform-specific compiler has its own default "alignment coefficient" (also known as the alignment modulus). Programmers can change this factor by precompiling the command #pragma pack(n), n=1,2,4,8,16, where n is the "alignment factor" you specify.

Rules:

1. Data member alignment rules: for data members of structure (struct)(or union (union)), the first data member is placed at the place where offset is 0, and the alignment of each data member shall be carried out according to the value specified by #pragma pack and the smaller of the data member's own length.

2. Overall alignment rules for structure (or union) : after the data members have aligned themselves, the structure (or union) itself should be aligned in accordance with the smaller of the values and structure (or union) maximum data member lengths specified by #pragma pack.

Explanation # 2:

VC's special handling of structured storage does improve the speed of CPU's storing variables, but it sometimes causes some trouble. We also mask the default alignment of variables and can set the alignment of variables ourselves. VC provides #pragma pack(n) to set variables to n byte alignment. n byte alignment means that the offset of the starting address of the variable is stored in two ways:

1. If n is greater than or equal to the number of bytes occupied by the variable, the offset must satisfy the default alignment.

2. If n is less than the number of bytes occupied by the type of the variable, the offset is a multiple of n, without satisfying the default alignment. The total size of the structure is also constrained by the following two conditions: if n is greater than the number of bytes occupied by all member variable types, then the total size of the structure must be a multiple of the space occupied by the largest variable. Otherwise it must be a multiple of n.

Here is an example of how to use it. #pragma pack(push) // save alignment

#pragma pack(4)// is set to 4 byte alignment

struct test {char m1; double m4; int m3; }; #pragma pack(pop)// restore the size of the above structure to 16:

Next, we will analyze its storage situation. First, we will allocate space for m1, whose offset is 0, satisfying our self-set alignment mode (4-byte alignment), and the size of m1 is 1 byte. Then start allocating space for m4, which has an offset of 1 and needs to be complemented by 3 bytes, so that the offset is a multiple of n=4 (because sizeof(double) is greater than 4), and m4 takes 8 bytes. Then allocate space for m3, which has an offset of 12 and satisfies a multiple of 4. m3 takes up 4 bytes. At this point, space has been allocated for all member variables, with a total of 16 bytes allocated, satisfying a multiple of n. If we change the #pragma pack(4) above to #pragma pack(8), we can get the size of the structure to be 24.

You see these text description head 1 must be numb, I insisted after reading, and then I wrote a program:


#pragma pack(4)

struct node{

 int e;
 char f;
 short int a;
 char b;

};

struct node n;

printf("%d\n",sizeof(n));

I calculated it to be 16, and the actual result was:

12

Then the data member inside the structure changes 1 position:


#pragma pack(4)

struct node{

 char f;
 int e;
 short int a;
 char b;};

struct node n;

printf("%d\n",sizeof(n));

12

Force alignment bits to position 2


#pragma pack(2)

struct node{

 char f;
 int e;
 short int a;
 char b;};

struct node n;

printf("%d\n",sizeof(n));

10

Force alignment bits to position 1


#pragma pack(1)

struct node{

 char f;
 int e;
 short int a;
 char b;};

struct node n;

printf("%d\n",sizeof(n));

8

Looking at the output results and text description a little dizzy, the following simple say 1 under my decision rules:

In fact, the reason for memory byte alignment mechanism is to minimize the number of memory reads. We know that CPU reads at least an order of magnitude faster than memory, so we have to sacrifice space for time in order to save computing time.

The following example shows how to minimize the number of reads.


#pragma pack(1)

struct node{

 char f;
 int e;
 short int a;
 char b;};

struct node n;

printf("%d\n",sizeof(n));

Here enforcement shall be carried out in accordance with the 1 byte alignment, can understand all of the content is carried out in accordance with the 1 byte read (understand it, because it can be well understood by the memory of the mechanism), all other data members are 1 byte integer times, so need not to carry on the memory of it, each member in memory is carried out in accordance with the actual order arrangement, structure of the actual length is 8


#pragma pack(2)

struct node{

 char f;
 int e;
 short int a;
 char b;};

struct node n;

printf("%d\n",sizeof(n));

This forces the 2 - byte alignment. If the memory distribution is still continuous, then int e will have to read CPU three times. So for the sake of "reading" int e, reserve 1BYTE after char f, and the last char b as well, so the length is 10


#pragma pack(4)

struct node{

 char f;
 int e;
 short int a;
 char b;};

struct node n;

printf("%d\n",sizeof(n));

This forces the four-byte alignment. Therefore, char f is reserved for 3BYTE, while short int a and char b can be read to CPU once (read according to 4 bytes), so the length is 12

The n value is invalid if n in #pramga pack(n) is greater than the number of bytes occupied by any one member of the struct. The compiler selects the maximum number of bytes of the data member in the structure as the reference


Related articles: