A quick understanding of
1, what is byte alignment?
in C, a struct is a composite data type whose constituent elements can be variables of a basic data type (such as int, long, float, and so on) or a data unit of some composite data types (such as arrays, structs, unions, and so on). In structs, the compiler allocates space for each member of the structure according to its natural boundary (alignment). Each member is stored sequentially in memory in the order in which they are declared, and the address of the first member is the same as the address of the entire structure.
In order for the CPU to be able to quickly access variables, the starting address of the variable should have some characteristics, called "alignment", such as a 4-byte int, whose starting address should be on a 4-byte boundary, where the starting address can be divisible by 4.
2, byte alignment What is the effect?
byte alignment is not only convenient for fast CPU access, but also a reasonable use of byte alignment can effectively save storage space.
for 32-bit machines, 4-byte alignment can increase the speed of CPU access, such as a long variable, if the 4-byte boundary is stored, then the CPU reads two times, so the efficiency is low. However, using a 1-byte or 2-byte alignment in a 32-bit machine can cause variable access speed to be reduced. So this takes into account the processor type, and also the compiler type. The default is 4-byte alignment in VC, and GNU GCC is also the default 4-byte alignment.
3, change the default byte alignment of the C compiler
By default, the C compiler allocates space for each variable or data cell according to its natural alignment criteria. In general, you can change the default alignment criteria by using the following method:
(1) with pseudo-directive #pragma pack (n), the C compiler will align N bytes,
(2) Use pseudo-directives #pragma Pack (), cancels custom byte alignment;
Second, byte alignment effect on program
Let's take a look at a few examples (32-bit, x86 environment, GCC compiler):
structure is defined as follows:
- struct A
- {
- int A;
- Char b;
- Short C;
- };
- struct B
- {
- Char b;
- int A;
- Short C;
- };
The lengths of the various data types on the 32-bit machine are now known as:
Char:1 (Signed and unsigned)
Short:2 (Signed and unsigned)
Int:4 (Signed and unsigned)
Long:4 (Signed and unsigned)
Float:4 Double:8
What about the size of the two structures above?
The result is:
sizeof (struct A) = 8
sizeof (struct B) = 12
Struct A contains a 4-byte-length int, a 1-byte-length char with a core 2-byte length of short data one, and B is the same; supposedly, A and B sizes should be the same, all 7 bytes.
The result above is because the compiler wants to align the data members spatially. The above is the result of the alignment according to the compiler's default settings, so can we change the compiler's default settings? Of course you can, for example:
- #pragma pack (2) //specify 2-byte alignment
- struct C
- {
- char b;
- int a;
- short C;
- };
- #pragma pack () //to cancel the specified alignment, restoring the default alignment
- sizeof (struct C) = 8
- Modify the Alignment to 1:
- #pragma pack (1) //specifies 1-byte alignment
- struct D
- {
- char b;
- int a;
- short C;
- };
- #pragma pack () //to cancel the specified alignment, restoring the default alignment
- sizeof (struct D) = 7
The following describes the role of #pragma pack ().
Third, the compiler is based on what the principle of alignment
Let's look at four important basic concepts:
(1) data type self-aligning value
For char type data, its own alignment value is 1, for the short type is 2, for int, float, double type, its own alignment value is 4, the unit byte.
(2) The self-aligning value of a struct or class
The value that is the largest of its members in its own alignment value.
(3) Specify the alignment value
The specified alignment value when the #pragma pack (value) is values.
(4) Valid alignment values for data members, structs, and classes: The value that is small for its own alignment value and for the specified alignment value.
With these values, we can easily discuss the members of a specific data structure and its own alignment. The valid alignment value n is the value that is ultimately used to determine how the data is stored, most importantly.
Effectively aligns N, which means "align on n". This means that the data "storage start address%n = 0". Data variables are arranged in the order in which they are defined. The starting address of the first data variable is the address of the structure. The member variables of the struct should be aligned, and the structure itself should be rounded according to its own valid alignment value (that is, the total length of the struct member variable takes up an integer multiple of the effective address value of the struct, as the following example understands). This makes it easy to understand the values of the above examples.
Example analysis, take B as an example.
- struct B
- {
- Char b;
- int A;
- Short C;
- };
assume that B starts discharging from the address space 0x0000. In this example, the specified alignment value is not defined, and in the author's environment, the value defaults to 4. The first member variable B has a self-aligning value of 1, which is smaller than the specified or default alignment value of 4, so its valid alignment value is 1, so its storage address 0x0000 conforms to 0x0000%1=0. The second member variable, a, has its own alignment value of 4, so the valid alignment value is also 4, so it can only be stored in four contiguous byte spaces with a starting address of 0x0004 through 0x0007, and the 0x0004%4=0 is reviewed and immediately adjacent 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 byte space of 0x0008 to 0x0009, conforming to 0x0008%2=0. So everything from 0x0000 to 0x0009 is stored in B content. Then look at the data structure B's own alignment value for its variable maximum alignment value (here is B) so is 4, so the structure of the effective alignment value is also 4. 0x0009 to 0x0000=10 bytes, (10+2)%4=0 according to the requirements of the structural rounding. So 0x0000a to 0x000b is also occupied by struct B. So B has a total of 12 bytes from 0x0000 to 0x000b, sizeof (struct B) = 12; In fact, if this is the case it has aligned the satisfied byte, because its starting address is 0, so it must be aligned, the reason is to add 2 bytes later, Because the compiler is in order to achieve the access efficiency of the array of structures, imagine if we define an array of struct B, then the first struct starts with a 0 no problem, but the second structure? As defined by the array, all elements in the array are next to each other, and if we do not add the size of the structure to the integer multiples of 4, Then the starting address for the next structure will be 0x0000a, which obviously does not satisfy the structure's address alignment, so we want to add the structure to an integer multiple of the effective alignment size. In fact, such as: for char data, its own alignment value of 1, for the short type of 2, for the int,float,double type, its own alignment value of 4, these existing types of self-aligning values are also based on the array, just because these types of length is known, So their own alignment values are already well-established.
Similarly, analyze the above example C.
- #pragma pack (2) /* specify by 2 byte alignment */
- struct C
- {
- & Nbsp; char b;
- int a;
- short C;
- };
- #pragma pack () /* to cancel the specified alignment, restore the default alignment */
The first variable B has its own alignment value of 1, the specified alignment value is 2, so its valid alignment value is 1, assuming that C starts from 0x0000, then B is stored in 0x0000, conforms to 0x0000%1=0, and the second variable, Its own alignment value is 4, the alignment value is 2, so the valid alignment value is 2, so the order is stored in 0x0002, 0x0003, 0x0004, 0x0005 four consecutive bytes, in accordance with 0x0002%2=0. The third variable C has its own alignment value of 2, so the valid alignment value is 2, which is stored in 0x0006, 0x0007, and conforms to 0x0006%2=0. So from 0x0000 to 0x00007 a total of eight bytes is stored in the C variable. and C has its own alignment value of 4, so the valid alignment value for C is 2. And 8%2=0,c only takes up eight bytes of 0x0000 to 0x0007. So sizeof (struct C) = 8.
Iv. How to modify the compiler's default alignment values
(1) in the VC IDE, you can modify: Project "Setting", the C + + TAB category of the Code generation option of the struct Member alignment modified, the default is 8 bytes;
(2) can be changed dynamically when encoding: # pragma pack. Note: It is pragma and not progma.
Five, for byte alignment, what we consider in programming
If you want to consider saving space when programming, then we only need to assume that the first address of the structure is 0, then the various variables are arranged according to the above principles, the basic principle is to make the variables in the structure of the type from small to large declaration, as far as possible to reduce the middle of the filling space. There is also a way to make space for the efficiency of time, we display the space to be filled to align. For example, there is a way of using space-time to explicitly insert reserved members:
- struct A
- {
- Char A;
- Char reserved[3];//use space to change time
- int b;
- };
Reversed members have no meaning to our program, it just fills the space to achieve byte alignment, and of course, even without this member, the compiler will usually give us the automatic filling of the alignment, we add it just play an explicit reminder role.
vi. possible pitfalls of byte alignment
Many of the pitfalls of alignment in code are implicit. For example, when forcing type conversions. For example:
unsigned int i = 0x12345678;
unsigned char *p=null;
unsigned short *p1=null;
p=&i;
*p=0x00;
p1= (unsigned short *) (p+1);
*p1=0x0000;
The last two lines of code, from the odd boundary to access the Unsignedshort variable, clearly do not conform to the rules of alignment.
On x86, similar operations can only affect efficiency, but on MIPS or SPARC, it can be an error because they require byte alignment.
Vii. How to find problems with byte alignment
If there is an alignment or assignment problem, first look at:
(1) compiler big/little terminal settings;
(2) See if the system itself supports aligned access;
(3) If the support, see Set the alignment or not, if not, then see the access needs to add some special decoration to mark its special access operation;
Viii. References
blog.csdn.net/xuegao007/article/details/1708349
BYTE Alignment 1