C language structure in data alignment
When I was on the C experiment class, I was sitting next to me asked me a question:
Struct
{
Char a;
INT B;
Double C;
SA;
SIZEOF (int) = 1; sizeof (int) = 4; SIZEOF (Double) = 8; SINEOF (SA) should be equal to 1 4 8 = 13 to, but when she programs the value of SIZEOF (SA) But 16, she asked me why?
I told her what I know: In order to speed up the CPU's access speed, the C compiler often calculates the size of the members in the structural variables while processing data, which is called data alignment (Data Alignment) ). SizeOf (SA) = 16 is for this reason, is not a program's error, but the compiler is caused by aligning the data to add 3 bytes of vacancy in the structure. Doing so may waste some memory, but the theoretical speed is fast.
After answering her question, I put a problem with myself. How is the data to it? I didn't know this problem, so I got back to bedroom, I did a few experiments, and I checked relevant information and finally concluded.
First, the development environment that should be explained is WinXP VC6, because different operating systems and different compilers, the result may not be the same. But the principle of different systems should be the same, so I hope that these efforts to do can help friends using other development environments.
Struct
{
Int a;
Char B;
SA;
Struct
{
Int a;
Char B;
Double C;
} SB;
Struct
{
Int a;
Double C;
Char B;
} SC;
Output Result: SizeOf (SA) = 8, SizeOf (SB) = 16, SIZEOF (SC) = 24;
Just look at SizeOf (SA), I think that the data inside the structure is stored in 4 bytes, so although Sizeof (char) = 1, the CHAR B in SA still occupies 4 words. Section, make SizeOf (SA) = 8, in order to verify my "guess", I made an experiment for SA:
Struct
{
Int a;
CHAR B, C, D, E ,;
} SA1;
Struct
{
Int a;
Char B;
INT C;
} SA2;
Output results: sizeof (sa1) = 8, SIZEOF (SA2) = 12;
It seems that the output has verified my "guess", so I tried to use the conclusion of me to explain SizeOf (SB) = 16, SIZEOF (SC) = 24;
Int a in SB accounts for 4 bytes, followed by 1 byte, but Char B then Double C needs to take 8 bytes, so CHAR B and DOUBLE C cannot be crowded in a 4 byte. Inside the unit. So fill in 3 bytes of vacancy between CHAR B and DOUBLE C, the alignment with its subsequent data, so it is not difficult to understand why sizeof (sa1) = 8 is.
I tried to understand SIZEOF (SC) = 24 in the same idea, but I encountered problems. Int a occupied by 4 bytes in SC, followed by Double C, and finally Char B occupies a byte, but in order to fill 4 bytes, CHAR B should fill 3 bytes. Air space. This should be equal to 4 8 4 = 16, but the result of the output is SIZEOF (SC) = 24. It seems that I have a problem with "guess". Where is the problem? Why didn't I analyze SA and SB according to my "guess", there is no problem in SC, what is the problem? The only difference between SB and SC is the order of the definition of Char B and Double C, resulting in the difference in SizeOf (SB) and SIZEOF (SC). The only explanation that can be thought of is different from SB and SC alignment. So I designed a group of contrast:
Struct
{
Int a;
INT D;
Double C;
Char B;
} SC1;
Struct
{
Int a;
Double C;
} SC2;
Output Result: SizeOf (SC1) = 24, SIZEOF (SC2) = 16;
The SC1 is equipped with INT D on the basis of INT A; however, SIZEOF (SC1) = 24 = SIZEOF (SC), this shows that there are 4 bytes of vacancy in the back of INT A. It seems that when this system is allocated to the variables in the structure, it is no longer like SA as a group of 4 bytes.
Look at SC2, just remove a char b, resulting in SIZEOF (SC2) = 16, which shows that there is seven bytes of vacancy after CHAR B. It can be seen that this system is a set of variables to the structure in a group in 8 bytes.
Comprehensive analysis of the above test results, SA is allocated to the variable distribution space in the structure in 4 bytes, thereby reaching the data alignment; SB and SC are allocated to the variable distribution space in the structure in the structure, thereby achieving Data alignment. Why is there a difference? Carefully observe that it is not difficult to find that the maximum type of space in SA is int type, while SizeOf (int) = 4; SB and SC occupied the most space of space is Double type, and sizeof (double) = 8; The system is based on the type of allocation space based on the type included in the structure.
After that, I did a few groups of tests on this issue, and the results obtained were the same as the above analysis.
In this way, when you encounter SizeOf, I don't have to wait until the output can see the value of SIZEOF, as long as you see the definition format within the Struct, you can calculate the actual value of SIZEOF.
After the conclusion, I have reviewed information related to SIZEOF, and found that the specific ways of the structure inside the structure can be specified inside and with compilation instructions, respectively:
1. Specify in #PRAGMA PACK (N) in the program
#pragma pack (1) allows the compiler to stay in Struct.
2, use compilation instructions
Use the CL / ZP switch, for example: CL / ZP8 specify data in units of 8 bytes in units of 8 bytes in units.
example:
CL / ZP8
#include
Using namespace std;
Struct // packing is 8
{
Int a;
Char B;
SA;
#pragma pack (push, 1) // Packing is now 1
Struct
{
Int a;
Char B;
Double C;
} SB;
#pragma pack (POP) // packing is 8
Struct
{
Int a;
Double C; Char B;
} SC;
Int main (void)
{
COUT << "SIZEOF (SA) =" << SIZEOF (SA) << endl
COUT << "SIZEOF (SB) =" << sizeof (sb) << ENDL;
COUT << "SIZEOF (SC) =" << SIZEOF (SC) << ENDL;
Return 0;
}
Output Result: SizeOf (SA) = 8, SizeOf (SB) = 13, SizeOf (SC) = 24
Another point must be pointed out: After setting the packing by #pragma pack (n), the compiler actually arranges the internal members of the structure, and does not necessarily, according to the N-specified length in #pragma Pack (n), Depending on the length of the maximum type of space within the structure. This may be to save space. E.g:
Struct // packing is 8
{
Int a;
Char B;
SA;
It is in four bytes when the members Int A and Char B are arranged. Since SizeOf (int) = 4 <8, it is arranged in 4 when aligned. However, when the Packing value is less than 4, it is arranged in units of packing values. and so:
Struct // packing is 8
{
Int a;
INT C;
Char B;
SA;
The output result is: SizeOf (SA) = 12; (in 4 bytes)
When the PACKING value is less than the number of bytes occupied by the most space occupied by the structure, it is based on the Packing value.
#pragma pack (push, 1) // Packing is now 1
Struct
{
Int a;
Char B;
Double C;
} SB;
The output result is: sizeof (sb) = 13; (in units of 1 byte)
C Builder can modify the Data Alignment in the Advanced Compiler page in the Options dialog box to be aligned by byte.
Attachment: Description of Pack in MSDN
#pragma pack (show | [n])
Specifies packing alignment for structure, union, and class members. Whereas the packing alignment of structures, unions, and classes is set for an entire translation unit by the / Zp option, the packing alignment is set at the data-declaration level by the pack Pragma. The pragma Takes Effect At The First Structure, Union, or Class Declaration After The Pragma Has No Effect On Definitions.
WHEN You #pragma Pack (N), WHERE N IS 1, 2, 4, 8, OR 16, EACH STRUCTURE MEMBER AFTER TYPEOR N-BYTE #Pragma Pack without an argument, structure members are packed to the value specified by / Zp. The default / Zp packing size is /Zp8.The show option causes the C4810 warning to issue, displaying the current pack value.
#pragma pack (show)
#pragma Pack (4)
#pragma pack (show)
Void main () {}
The Compiler Also Supports the Following Enhanced Syntax:
#pragma pack ([[{Push | POP},] [Identifier,]] [N])
...................
Each occurrence of a pack pragma with a push argument stores the current packing alignment on an internal compiler stack. The pragma's argument list is read from left to right. If you use push, the current packing value is stored. If you provide a value for N, That Value Becomes The New Packing Value. if you specify An Identifier, a name of your choosing, the ide associated with the new packing value.
Each occurrence of a pack pragma with a pop argument retrieves the value at the top of an internal compiler stack and makes that value the new packing alignment. If you use pop and the internal compiler stack is empty, the alignment value is that set from the command-line and a warning is issued. If you use pop and specify a value for n, that value becomes the new packing value. If you use pop and specify an identifier, all values stored on the stack are removed from the stack until a matching identifier is found. The packing value associated with the identifier is also removed from the stack and the packing value that existed just before the identifier was pushed becomes the new packing value. If no matching identifier is found, the packing value set from the command line is used and a level-one warning is issued. The default packing alignment is 8.The new, enhanced functionality of the pack pragma allows you to write header files that ensure that packing values are the same before an D after the header file is encountered:
/ * File name: incrude1.h
* /
#pragma pack (push, enter_includ1)
/ * Your incrude-file code ... * /
#pragma pack (POP, ENTER_INCLUDE1)
/ * End of incrude1.h * /
In the previous example, the current pack value is associated with the identifier enter_include1 and pushed, remembered, on entry to the header file. The pack pragma at the end of the header file removes all intervening pack values that may have occurred in the header file And Removes The Pack Value Associated with EnSures That The Pack Value Is The Same Before Andreat The Header File.
The new functionality also allows you to use code, such as header files, that uses pack pragmas to set packing alignments that differ from the packing value set in your code: #pragma pack (push, before_include1)
#include "include" include1.h "
#pragma pack (Pop, Before_Include1)
.