Explanation of C language byte alignment
1. What is byte alignment?
In modern computers, memory space is divided by byte. Theoretically, it seems that access to any type of variable can start from any address, but the actual situation is that when accessing a specific variable, it is often accessed at a specific memory address, rather than sequential emissions. To enable the CPU to quickly access variables, the starting address of the variable should have some characteristics, that is, the so-called "Byte alignment ". For example, the starting address of a 4-byte int type should be located at the boundary of 4 bytes, that is, the starting address can be divisible by 4.
In C, struct is a composite data type, and its components can be both variables of basic data types (such as int, long, float, and so on, it can also be a data unit of a composite data type (such as an array, struct, or union. In a struct, the compiler allocates space for each member of the struct according to its natural boundary (alignment). Each member is stored in the memory in sequence according to the declared sequence, the address of the first member is the same as the address of the entire structure.
Ii. Role and cause of byte alignment
The processing of buckets varies greatly by hardware platform. Some platforms (such as the iSCSI system is very strict in byte alignment) can only access certain types of data from some specific addresses. This may not happen on other platforms. However, alignment of data storage according to the requirements suitable for their platforms may result in a loss of access efficiency. For example, for some platforms (such as x86), each read starts from an even address. If an int type (assuming 32-bit) is stored at the beginning of the even address, one read cycle can be read. If it is stored at the beginning of the odd address, two read cycles are required, the int type data can be obtained only when the high and low bytes of the two read results are pieced together. The latter is obviously much less efficient in reading, but the storage space may be more compact than the former, which is also a trade-off between space and time.
Iii. byte alignment Principle
What principles does the compiler align? Before we continue to analyze specific bytes alignment problems, let's take a look at several important basic concepts:
1. alignment value of the Data Type itself: On a 32-bit x86 machine, the alignment value of the char type data itself is 1 byte; for the short type, alignment is 2 bytes; for int, long, and float types, the alignment value is 4 bytes;
For long, the double type is 8 bytes. For pointer types of basic types (which are essentially unsigned long type), their own alignment is 4 bytes.
2. The alignment value of a struct or class: The value with the largest alignment value among its members.
3. Specify the alignment value: # The alignment value specified when pragma pack (value) is used.
4. Default alignment value of the compiler: Generally, the alignment value is the same as the number of CPU characters in length. The alignment value is 4 bytes on 32-bit machines and 8 bytes on 64-bit machines. If no alignment value is specified, the compiler uses the default alignment value.
5. Valid alignment values of data members, struct, and classes: the alignment value of the data itself and the value smaller than the specified alignment value.
With these values, we can easily discuss the data structure members and their alignment. The valid alignment value N is the final value used to determine the data storage address. Valid alignment indicates "alignment on N", that is, the "Storage Start address % N = 0" of the data ". data variables in the data structure are discharged in the defined order. The starting address of the first data variable is the starting address of the data structure. The member variables of the struct must be aligned and discharged, and the struct itself must be rounded according to its own valid alignment values (that is, the total length occupied by the member variables of the struct must be several times the effective alignment value of the struct.
Iv. byte alignment Example Analysis
According to the byte alignment principle and the following examples, we will understand.
Example Analysis:
Analysis example B;
Struct B {
Char B;
Int;
Short c;
};
Assume that B is discharged from the address space 0x0000. The alignment value is not defined in this example. In the author's environment, this value is 4 by default. The first member variable B's own alignment value is 1, which is smaller than the specified or default alignment value 4, so its valid alignment value is 1, therefore, the storage address 0x0000 is 0 x 0000% 1 = 0. the alignment value of the second member variable a is 4, so the valid alignment value is 4. Therefore, it can only be stored in the four consecutive bytes from the starting address 0x0004 to 0x0007, review 0 x 0004% 4 = 0, which is close to the first variable. The third variable c has its own alignment value of 2, so the valid alignment value is also 2, which can be stored in the two bytes from 0x0008 to 0x0009, Which is 0 x 0008% 2 = 0. Therefore, B content is stored from 0x0000 to 0x0009. Then, let's look at the alignment value of Data Structure B as the maximum alignment value in its variable (here it is B), so it is 4, so the valid alignment value of the structure is also 4. According to the requirements of the structure, 0x0009 to 0x0000 = 10 bytes, (10 + 2) % 4 = 0. Therefore, 0x0000A to 0x000B is also occupied by struct B. Therefore, B has 12 bytes from 0x0000 to 0x000B, and sizeof (struct B) = 12;
Similarly, analyze the above example C:
# Pragma pack (2)/* specify to align by 2 bytes */
Struct C {
Char B;
Int;
Short c;
};
# Pragma pack ()/* cancel the specified alignment and restore the default alignment */
The first variable B's own alignment value is 1 and the specified alignment value is 2. Therefore, the valid alignment value of B is 1. Suppose C starts from 0x0000, then B is stored in 0x0000, conforms to 0 x 0000% 1 = 0; the second variable, its own alignment value is 4, and the specified alignment value is 2, so the valid alignment value is 2, therefore, the sequence is stored in four consecutive bytes, namely 0x0002, 0x0003, 0x0004, and 0 x 0002%. The alignment value of the third variable c is 2, so the valid alignment value is 2, which is stored in sequence.
In 0x0006, 0x0007, 0 x 0006% 2 = 0. Therefore, from 0x0000 to 0x00007, a total of eight characters are stored in the C variable. And C's own alignment value is 4, so the valid alignment value of C is 2. Again 8% 2 = 0, C only occupies eight bytes from 0x0000 to 0x0007. So sizeof (struct C) = 8.
V. Summary
With the above explanation, I believe you should have a clear understanding of the concept of byte alignment in C language. In network programs, it is very important to master this concept. A binary stream (such as a struct) is transmitted between different platforms (such as between Windows and Linux ), therefore, the two platforms must define the same alignment mode and pay attention to the large and small-end bytes. Otherwise, some strange errors may occur inexplicably, but it is very difficult to troubleshoot.
Vi. Source Code
[Cpp]View plaincopyprint?
- /*************************************** * *********************************** Copyright by Javacode007, all rights reserved!
- Filename: structsize. c Author: Javacode007
- Date: Version: 1.0
- Description: test the struct type ************************************ **************************************** **/
- # Include
- Struct {
- Char c; short s;
- Int I ;};
-
- # Pragma pack (1)/* specify to align by 1 byte */struct PA
- {Char c;
- Short s; int I;
- }; # Pragma pack ()/* cancel the specified alignment and restore the default alignment */
-
- Struct B {
- Char c; int I;
- Short s ;};
- # Pragma pack (2)/* specify to align by 2 bytes */
- Struct PB {
- Char c; int I;
- Short s ;};
- # Pragma pack ()/* cancel the specified alignment and restore the default alignment */
-
- Int main (){
- Struct A stA; struct PA stPA;
- Struct B stB; struct PB stPB;
-
- Printf ("sizeof (A) = % d, & c = % p, & s = % p, & I = % p \ r \ n", sizeof (stA ), & stA. c, & stA. s, & stA. i); printf ("sizeof (PA) = % d, & c = % p, & s = % p, & I = % p \ r \ n ", sizeof (stPA), & stPA. c, & stPA. s, & stPA. I );
- Printf ("sizeof (B) = % d, & c = % p, & s = % p, & I = % p \ r \ n", sizeof (stB ), & stB. c, & stB. s, & stB. i); printf ("sizeof (PB) = % d, & c = % p, & s = % p, & I = % p \ r \ n ", sizeof (stPB), & stPB. c, & stPB. s, & stPB. I );
-
- Return 0;
- }
/*************************************** * *********************************** Copyright by Javacode007, all rights reserved! Filename: structsize. cAuthor: Javacode007Date: 2012-8-5Version: 1.0 Description: test the struct type ************************************ **************************************** **/# include
Struct A {char c; short s; int I ;};# pragma pack (1)/* specify to align by 1 byte */struct PA {char c; short s; int I ;};# pragma pack ()/* cancel the specified alignment and restore the default alignment */struct B {char c; int I; short s ;}; # pragma pack (2)/* specify to align by 2 bytes */struct PB {char c; int I; short s ;};# pragma pack ()/* cancel the specified alignment, restore Default alignment */int main () {struct A stA; struct PA stPA; struct B stB; struct PB stPB; printf ("sizeof (A) = % d, & c = % p, & s = % p, & I = % p \ r \ n ", sizeof (stA), & stA. c, & stA. s, & stA. i); printf ("sizeof (PA) = % d, & c = % p, & s = % p, & I = % p \ r \ n ", sizeof (stPA), & stPA. c, & stPA. s, & stPA. i); printf ("sizeof (B) = % d, & c = % p, & s = % p, & I = % p \ r \ n ", sizeof (stB), & stB. c, & stB. s, & stB. i); printf ("sizeof (PB) = % d, & c = % p, & s = % p, & I = % p \ r \ n ", sizeof (stPB), & stPB. c, & stPB. s, & stPB. i); return 0 ;}
Output result: