Typedef struct
{
Uint32 numelements;
Union
{
Uint32 objecthandle;
} Entry;
} Str_array, * pstr_array;
These two more statements # pragma pack (push, 1)
# Pragma pack (POP)
# Pragma pack ([N])
This command specifies the Compact alignment between the structure and the federated members. The structure and Union of a complete conversion unit
The Compact alignment is set by the/z p option. Compact alignment is configured at the data description layer with instructions of p a c e compilation. The
The Compilation instruction takes effect in the first structure or joint description after it appears. This compilation instruction is invalid for the definition.
When you use # pragma pack (N), Here N is 1, 2, 4, 8 or 1 6. The first structure member
Each structure member is stored in a smaller Member type or N-byte limit. If you use none
Parameter # pragma pack, the structure member is compact to the value specified by/z p. The default/z p compact value is
/Z p 8.
The compiler also supports the following enhanced Syntax:
# Pragma pack ([{p u s h | p o p},] [identifier,] [N])
If different components use the p a c k Compilation instruction to specify different compact alignment, this syntax allows you
Components are combined into a separate conversion unit.
Each appearance of the p a c k compilation indication with the p u s h Parameter stores the current Compact alignment into an internal code
The interpreter stack. The compilation indicator parameter table is read from left to right. If you use p u s h, the current Compact
Value is stored; if you give a value of N, the value will become a new compact value. If you specify
Identifier, that is, if you select a name, the identifier will be associated with the new compact value.
The top value of the internal compiler stack will be retrieved every time the p a c k Compilation instruction with a p o p parameter appears,
And make this value a new compact alignment value. If you use the p o p parameter and the internal compiler stack is empty,
The Compact value is the value given by the command line and a warning message is generated. If you use p o p and specify
N, which will become a new compact value.
If you use p o p and specify an identifier, all values stored in the stack will be deleted from the stack
To a matched identifier, this compact value related to the identifier is also removed from the stack, and this only
The Compact value that existed before the identifier entered the stack becomes the new compact value. If no matching identifier is found
Compact value set with command line, and a level-1 warning will be generated. The default compact alignment is 8.
The new enhancements of the p a c k compilation Directive allow you to write header files to ensure that before and after the header file
Compact values are the same.
What is memory alignment?
Consider the following structure:
Struct foo
{
Char C1;
Short S;
Char C2;
Int I;
};
Assume that the members of this structure are in a compact arrangement in the memory. If the C1 address is 0, the s address should be 1, and the C2 address is 3, the address of I is 4. That is
C1 00000000, s 00000001, C2 00000003, I 00000004.
However, we write a simple program in Visual C/C ++ 6:
Struct Foo;
Printf ("C1% P, S % P, C2 % P, I % P/N ",
(Unsigned INT) (void *) & A. C1-(unsigned INT) (void *) &,
(Unsigned INT) (void *) & A. S-(unsigned INT) (void *) &,
(Unsigned INT) (void *) & A. C2-(unsigned INT) (void *) &,
(Unsigned INT) (void *) & A. I-(unsigned INT) (void *) & );
Run and output:
C1 00000000, s 00000002, C2 00000004, I 00000008.
Why? This is a problem caused by memory alignment.
Why memory alignment
The following content is excerpted from Intel architecture 32 manual.
Words, dual words, and four words do not need to be aligned in the memory on the natural boundary. (For words, double words, and four words, the natural boundary is an even number of addresses, which can be divided by four, and an address that can be divided by eight .)
In any case, data structures (especially stacks) should be aligned as much as possible on natural boundaries to improve program performance. The reason is that the processor needs to perform two memory accesses to access non-alignment memory; however, alignment memory access only needs one access.
A single-or dual-character operand spans the 4-byte boundary, or a four-character operand spans the 8-byte boundary, which is considered not aligned and thus requires two bus cycles to access the memory. The starting address of a word is odd, but it does not span the word boundary. It is considered to be aligned and can be accessed in a bus cycle.
Some operations require memory operations to be aligned on the natural boundary. If the operands are not aligned, these commands generate a general protection exception (# GP ). The natural boundary of dual words is the address that can be divided by 16 characters. Other double-byte commands allow non-alignment access (without common protection exceptions). However, additional memory bus cycles are required to access non-alignment data in the memory.
Processing of memory alignment by the compiler
By default, the C/C ++ compiler performs memory alignment for the member data in the structure and stack by default. Therefore, the output of the above program becomes:
C1 00000000, s 00000002, C2 00000004, I 00000008.
The compiler shifts unaligned members to the backend, alignment each Member to the natural boundary, which leads to a larger size of the entire structure. Although it sacrifices a little space (there are holes between members), it improves performance.
For this reason, we cannot assert sizeof (FOO) = 8. In this example, sizeof (FOO) = 12.
How to avoid the impact of memory alignment
So can we both improve performance and save some space? TIPS. For example, we can change the above structure:
Struct bar
{
Char C1;
Char C2;
Short S;
Int I;
};
In this way, each member is aligned on its natural boundary, thus avoiding the automatic alignment of the compiler. In this example, sizeof (bar) = 8.
This technique plays an important role, especially when the structure is provided to third-party developers as part of the API. Third-party developers may change the default alignment options of the compiler, causing this structure to use some Alignment Method in your released DLL, while where third-party developers use another Alignment Method. This will cause major problems.
For example, in the foo structure, our DLL uses the default alignment option, alignment is
C1 00000000, s 00000002, C2 00000004, I 00000008, and sizeof (FOO) = 12.
The third party closes the alignment option, resulting in
C1 00000000, s 00000001, C2 00000003, I 00000004, and sizeof (FOO) = 8.
How to Use alignment options in C/C ++
The compilation options in vc6 include/ZP [1 | 2 | 4 | 8 | 16]./zp1 indicates alignment at the boundary of 1 byte, and zpn indicates alignment at the boundary of n Bytes. The N-byte boundary alignment means that the address of a member must be arranged on an integer multiple address of the member size or an integer multiple address of N, and the minimum values of the two must be obtained. That is:
Min (sizeof (Member), n)
In fact, the one-byte boundary alignment means that there is no holes between the structure members.
The/zpn option is applied to the entire project and affects all structures involved in compilation.
To use this option, you can open the project properties page in vc6, C/C ++ page, select the code generation category, and select in struct member alignment.
To use alignment options for some schema definitions, use the # pragma pack compilation command. Command syntax:
# Pragma pack ([show] | [push | Pop] [, identifier], n)
The meaning is the same as that of the/zpn option. For example:
# Pragma pack (1)
Struct foo_pack
{
Char C1;
Short S;
Char C2;
Int I;
};
# Pragma pack ()
Stack memory alignment
We can observe that the stack alignment in vc6 is not affected by the alignment option of the structure member. (There are two things ). It always maintains alignment and alignment on the 4-byte boundary.
Verification Code
# Include <stdio. h>
Struct foo
{
Char C1;
Short S;
Char C2;
Int I;
};
Struct bar
{
Char C1;
Char C2;
Short S;
Int I;
};
# Pragma pack (1)
Struct foo_pack
{
Char C1;
Short S;
Char C2;
Int I;
};
# Pragma pack ()
Int main (INT argc, char * argv [])
{
Char C1;
Short S;
Char C2;
Int I;
Struct Foo;
Struct Bar B;
Struct foo_pack P;
Printf ("Stack C1 % P, S % P, C2 % P, I % P/N ",
(Unsigned INT) (void *) & C1-(unsigned INT) (void *) & I,
(Unsigned INT) (void *) & S-(unsigned INT) (void *) & I,
(Unsigned INT) (void *) & C2-(unsigned INT) (void *) & I,
(Unsigned INT) (void *) & I-(unsigned INT) (void *) & I );
Printf ("struct Foo C1 % P, S % P, C2 % P, I % P/N ",
(Unsigned INT) (void *) & A. C1-(unsigned INT) (void *) &,
(Unsigned INT) (void *) & A. S-(unsigned INT) (void *) &,
(Unsigned INT) (void *) & A. C2-(unsigned INT) (void *) &,
(Unsigned INT) (void *) & A. I-(unsigned INT) (void *) & );
Printf ("struct bar C1 % P, C2 % P, S % P, I % P/N ",
(Unsigned INT) (void *) & B. C1-(unsigned INT) (void *) & B,
(Unsigned INT) (void *) & B. C2-(unsigned INT) (void *) & B,
(Unsigned INT) (void *) & B. S-(unsigned INT) (void *) & B,
(Unsigned INT) (void *) & B. I-(unsigned INT) (void *) & B );
Printf ("struct foo_pack C1 % P, S % P, C2 % P, I % P/N ",
(Unsigned INT) (void *) & P. C1-(unsigned INT) (void *) & P,
(Unsigned INT) (void *) & p.s-(unsigned INT) (void *) & P,
(Unsigned INT) (void *) & P. C2-(unsigned INT) (void *) & P,
(Unsigned INT) (void *) & P. I-(unsigned INT) (void *) & P );
Printf ("sizeof foo is % d/N", sizeof (FOO ));
Printf ("sizeof bar is % d/N", sizeof (bar ));
Printf ("sizeof foo_pack is % d/N", sizeof (foo_pack ));
Return 0;
}