Memory alignment problem

xiaoxiao2021-03-06  45

TypedEf struct {uint32 NumeLements; union {uint32 ObjectHandle;} entry;} str_array, * pstr_Array;

There are also two #pragma packs (push, 1) #pragma pack (POP) #pragma pack ([n]) This instruction specifies the compact alignment of the structure and the federation. The structure of a complete conversion unit and the combined compact alignment are set by / zp option. Compact alignment Pack compiles instructions in the data sheet setting. This compilation indication takes effect at the first structure or joint description thereof. This compilation indication is invalid for the definition. When you use #pragma pack (n), the N is 1, 2, 4, 8 or 16 here. Each struct member after the first structural member is stored in a smaller member type or N-byte limits. If you use a non-reflected #pragma Pack, the structural member is compact to the value specified by / zp. This default / zp compact value is / zp8. The compiler also supports the following enhanced grammar: #pragma pack ([[{PUSH | POP},] [Identifier,]]] [N]) If the different components use the PACK compile indication to specify different compact alignment, this syntax allows you Combining program components into a separate conversion unit. Each appearance of the PUSH parameter is stored in an internal compiler stack each appearing with a Push parade. The parameter table of the compilation indication is read from left to right. If you use push, the current compact value is stored; if you give a N value, this value will become a new compact value. If you specify an identifier, you select a name, then the identifier will link with this new compact value. Each appearance of a PACK compilation indication with a POP parameter retrieves the value of the internal compiler stack and makes the value a new compact alignment value. If you use the POP parade and the internal compiler stack is empty, the compact value is a value given by the command line, and will generate a warning message. This value will become a new compact value if you use POP and specify a value. If you use POP and specify an identifier, all the values ​​stored in the stack will remove from the stack until a matching identifier is found, this compact value related to the identifier is also removed from the stack, and this is only identified The compact value exists before the stack becomes a new compact value. If the matching identifier is not found, the compact value set by the command line will be used, and one level warning will be generated. The default is more compact alignment 8. The new enhancement of the Pack compile indication allows you to write the header file to ensure that the compact value before and after the header is encountered. What is memory? Consider the following structure: struct foo {char C1; short s; char C2; int i;}; assuming that the member of this structure is compactly arranged in memory, suppose the address of the C1 is 0, then the address of S should be 1 The address of the C2 is 3, i's address is 4. That is, the C1 million00000, S 00000001, C2 00000003, i 00000004, we write a simple program in Visual C / C 6: Struct Foo A; Printf ("C1% P, S% P, C2% P, I% P / N ", (unsigned int) (void *) & a.c1 - (unsigned int) & a, (unsigned int) & a.s - (unsigned int) (void *) & A, Unsigned int) (void *) & a.c2 - (unsigned int) & a, (unsigned int) & a.i - (unsigned int) (void *) & a); run, output: c1 00000000 , S 00000002, C2 00000004, i 00000008. Why is this this? This is the problem caused by memory alignment. Why do you have memory?

The following segments are selected from "Intel Architecture 32 Manual". Word, double word (dword), and quadrigraphic don't need to be aligned in memory on the natural boundary. (For "words", "double words", and "four words", the natural boundaries are even addresses, and can be 4 complete addresses, and the address that can be completely removed.) In addition, in order to improve the performance of the program The data structure (especially stack) should be aligned on the natural boundary as much as possible. The reason is that in order to access unsigned memory, the processor needs two memory access; however, the aligned memory access only needs to be accessed. A word or double word operance spans the 4-byte boundary, or a four-character operand spans the 8-byte boundary, which is considered to be unsigned, which requires two bus cycles to access memory. A word start address is an odd number but there is no leapfrog that is considered to be aligned, and can be accessed in a bus cycle. Some operational double four words require memory operations to align in the natural boundary. If the operand is not aligned, these instructions will generate a universal protection exception (#GP). The natural boundary of the double four word is the address that can be tied to the 16. Other operational double four words allow unconfigured access (no universal protection exception), however, additional memory bus cycles are required to access unsigned data in memory. The compiler defaults to the memory-aligned processing default, the C / C compiler defaults to the structure and the member data in the stack. Therefore, the above program output becomes: C1 00000000, S 00000002, C2 00000004, i 00000008. The compiler will move the unsigned member to the backward, and each member is aligned to the natural boundary, which has also caused the size of the entire structure to be large. Although it will sacrifice a little space (there is a void between members), performance is improved. It is also this reason, we can't assert SIZEOF (FOO) == 8. In this example, SIZEOF (FOO) == 12.

How to avoid the impact of memory

So, can you achieve the purpose of improving performance, save a little space? There is a little tip that can be used. For example, we can change the above structure:

Struct bar {char C1; char C2; short s; int i;}; so, each member is aligned with its natural boundary, thereby avoiding auto-alignment of the compiler. In this example, SizeOf (BAR) == 8.

This tip has an important role, especially when this structure is provided to third parties as part of the API. Third-party developers may change the default alignment option of the compiler to cause this structure to use some alignment in your released DLL, and where to use another alignment in the third party developer. This will lead to major problems. For example, the FOO structure, our DLL uses the default alignment option, aligned to C1 00000000, S 00000002, C2 00000004, i 00000008, while SIZEOF (FOO) == 12. The third party closes the alignment option, causing the C1 00000000, S 00000001, C2 00000003, i 00000004, while SIZEOF (FOO) == 8.

How to use alignment options in C / C

The compilation options in the VC6 are / zp [1 | 2 | 4 | 8 | 16], / zp1 indicates that the 1-byte boundary is aligned, corresponding, / ZPN is aligned in the n-byte boundary. The N-byte boundary is aligned. The address of a member must be arranged on an integer multiple of the member's size or an integer multiple of N to take the minimum of them. That is: MIN (Sizeof (MEMBER), N) actually, and the 1-byte boundary is aligned with no vacuum between structural members. The / ZPN option is applied to the entire project, affecting all the structures involved in compilation. To use this option, you can open the engineering property page, C / C page in VC6, select the Code Generation classification, and select it in Struct Member Alignment. To use the alignment option specifically for some structural definitions, you can use the #pragma Pack to compile instructions. The instruction syntax is as follows: #pragma pack ([Show] | [Push | POP] [, Identifier], N) meaning and / ZPN options are the same. such as:

#pragma pack (1) struct foo_pack {char C1; Short S; CHAR C2; INT I;}; #pragma pack ()

Stack memory

We can observe that alignment in the stack in VC6 is not affected by structural members alignment options. (Or two is two yards). It is always aligned and is aligned on the 4-byte boundary.

Verify code

#include

Struct foo {char C1; short s; char C2; int 1;

Struct bar {char C1; char C2; short s; int 1;};

#pragma pack (1) struct foo_pack {char C1; Short S; CHAR C2; INT i;}; # prgma pack ()

INT Main (int Argc, char * argv []) {char C1; short s; char C2; INT I; struct foo a; struct bar b; struct foo_pack p;

转载请注明原文地址:https://www.9cbs.com/read-57718.html

New Post(0)