Memory alignment issues and pragma pack commands in C/

Source: Internet
Author: User

This memory alignment problem actually affects the result value of sizeof (struct). Suddenly think of a previously written API library, there is an API to the background service program to send a socket request. The socket packet is a struct. The length of the data is detected before the socket is sent, and the length is detected after the server receives the data. If the memory alignment problem affects the structure of sizeof, then the socket sends the structure of the time, how is it sent? Does the sent content contain "holes" in the structure? If the alignment in the API library is not set, then the sizeof result of the server and client will be different, which will cause many problems?

The following text describes the principle of this mechanism. There is no analysis of the API library for this principle, go back and have a good look.

Reprinted from Http://www.cppblog.com/xczhang/archive/2007/12/23/39396.html

First of all, let's look at the following code:

struct     {      UINT32  numelements;      Union      {         UINT32  objecthandle;       } Entry;      *pstr_array;

And these two sentences.

    #pragma Pack (push, 1)    #pragma pack (POP)

#pragma pack ([n])

This instruction specifies the compact alignment of the structure and the union members. While the structure of a complete conversion unit and the combined compact alignment are set by the/Z p option. Compact alignment is set in the data Description layer with p a C-e compilation instructions. The compilation instruction takes effect at the first structure or joint description after it appears. The compilation indicates that the definition is invalid. When you use #pragma pack (n), here n is 1, 2, 4, 8, or 1 6. Each struct member after the first struct member is stored within a smaller member type or an n-byte boundary. If you use the #pragma pack without parameters, the structure members are compact to the value specified in/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 p a C K compilation instructions to specify different compact alignments, this syntax allows you to combine program components into a single unit of conversion. Each occurrence of the p a C K compiler with P u S h parameter will store the current compact alignment in an internal compiler stack. The parameter table for compiling instructions 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 becomes the new compact value. If you specify a
identifier, that is, if you select a name, the identifier will be associated with this new compact value. Each occurrence of the p a C K compiler with a P o parameter retrieves the value of the top of the internal compiler stack and causes the value to be 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 a
A value of n, which becomes the new compact value. If you use P O p and specify an identifier, all values stored on the stack are removed from the stack until a matching identifier is found, and the compact value associated with the identifier is also removed from the stack, and this compact value that exists only before the identifier is placed in the stack becomes the new compact value. If no matching identifiers are found, the compact values set by the command line will be used, and a first level warning will be generated. The default compact alignment is 8. The new enhancements to the p a C K compilation instructions let you write the header file to ensure that the compact values are the same before and after the header file is encountered.

What is memory alignment

Consider the following structure:

struct Foo {   char  C1;     Short s;    Char C2;    int i;};

Assuming that the members of this structure are compact in memory, assuming that the address of C1 is 0, then the address of S should be 1,C2 address or 3,i address is 4. That is

C1 00000000, S 00000001, C2 00000003, I 00000004.

However, we are writing a simple program in Visual C + + 6:

        structFoo A; printf ("C1%p, S%p, C2%p, I%p\n", (unsignedint)(void*) &a.c1-(unsignedint)(void*) &A, (unsignedint)(void*) &a.s-(unsignedint)(void*) &A, (unsignedint)(void*) &A.C2-(unsignedint)(void*) &A, (unsignedint)(void*) &A.I-(unsignedint)(void*) &a);

Run, Output:

C1 00000000, S 00000002, C2 00000004, I 00000008.

Why is that? This is the problem caused by memory alignment.

Why there is memory alignment

The following excerpt from Intel Architecture Manual.
Word, double word, and four words do not need to be aligned in memory on natural boundaries. (for words, double words, and four words, the natural boundary is an even address, an address that can be divisible by 4, and an address divisible by 8.) )
In any case, in order to improve the performance of the program, data structures (especially stacks) should be aligned as far as possible on natural boundaries. The reason is that in order to access unaligned memory, the processor needs to make two memory accesses; However, aligned memory access requires only one access.
A word or double-word operand spans a 4-byte boundary, or a four-word operand spans 8-byte boundaries, is considered unaligned, and requires two bus cycles to access memory. A word start address is odd but does not span a word boundary is considered to be aligned and can be accessed during a bus cycle.
Some operations with a four-word instruction require that the number of memory operands be aligned on the natural boundary. If the operands are not aligned, these instructions will produce a generic protection exception (#GP). A four-word natural boundary is an address that can be divisible by 16. Other operations with a double four-word instruction allow unaligned access (no generic protection exception), however, additional memory bus cycles are required to access misaligned data in memory.

compiler handling of memory alignment

By default, the C + + compiler defaults The structure, the member data in the stack, to memory alignment. As a result, the above program output becomes:
C1 00000000, S 00000002, C2 00000004, I 00000008.
The compiler moves the unaligned members backward, aligning each member to the natural boundary, which also causes the size of the entire structure to become larger. While sacrificing a little space (there are holes in the members), it improves performance.
It is for this reason that we cannot assert that sizeof (foo) = = 8. In this example, sizeof (foo) = = 12.

How to avoid the effect of memory alignment

So, can you achieve the goal of improving performance, but also save a bit of space? There is a little bit of skill to use. For example, we can change the above structure to:

struct BAR
{
Char C1;
Char C2;
Short S;
int i;
};
This way, each member is aligned on its natural boundary, thus avoiding the compiler's automatic alignment. In this example, sizeof (bar) = = 8.

This technique has an important role to play, especially when this structure is provided as part of the API for third-party development use. Third-party developers may change the compiler's default alignment options, causing the structure to use some sort of alignment in your published DLL, while the third-party developer uses a different alignment. This will lead to major problems.
For example, the Foo structure, our DLLs use the default alignment option, for arranges
C1 00000000, S 00000002, C2 00000004, I 00000008, while sizeof (foo) = = 12.
And the third party turns the alignment option off, causing
C1 00000000, S 00000001, C2 00000003, I 00000004, while sizeof (foo) = = 8.

How to use the alignment options in C + +

The compilation options in VC6 are/zp[1|2|4|8| /ZP1 represents a 1-byte boundary alignment, and the corresponding/ZPN represents an n-byte boundary alignment. N-byte boundary alignment means that the address of a member must be arranged on an integer-multiple address of the member's size or an integer-multiple address of N, taking the minimum value from them. That is
Min (sizeof (member), N)
In fact, a 1-byte boundary alignment also indicates that there are no voids between struct members.
The/ZPN option is applied to the entire project, affecting all the constructs that participate in the compilation.
To use this option, you can open the Project Properties page in VC6, C + + pages, select the code Generation category, and select the struct member alignment.

To use the alignment options specifically for certain structure definitions, you can use the #pragma pack compilation directives. The instruction syntax is as follows:
#pragma pack ([show] | [Push | pop] [, identifier], N)
The meaning and/ZPN options are the same. Like what:

    #pragma Pack (1)    struct  foo_pack    {        char  C1;          Short s;         Char C2;         int i;    };     #pragma pack ()

Stack memory Alignment

We can observe that the alignment of the stack in VC6 is not affected by the structure member alignment options. (It's a different thing). It is always aligned and aligned on a 4-byte boundary.

Consider the following validation code:

1#include <stdio.h>2 3     structFoo4     {5         CharC1;6          Shorts;7         CharC2;8         inti;9     };Ten  One     structBar A     { -         CharC1; -         CharC2; the          Shorts; -         inti; -     }; -  +     #pragmaPack (1) -     structFoo_pack +     { A         CharC1; at          Shorts; -         CharC2; -         inti; -     }; -     #pragmaPack () -  in  -     intMainintargcChar*argv[]) to     { +         CharC1; -          Shorts; the         CharC2; *         inti; $ Panax Notoginseng     structfoo A; -     structBar B; the     structFoo_pack p; +  Aprintf"Stack C1%p, S%p, C2%p, I%p\n", the(unsignedint)(void*) &AMP;C1-(unsignedint)(void*) &I, +(unsignedint)(void*) &s-(unsignedint)(void*) &I, -(unsignedint)(void*) &AMP;C2-(unsignedint)(void*) &I, $(unsignedint)(void*) &i-(unsignedint)(void*) &i); $  -printf"struct Foo C1%p, S%p, C2%p, I%p\n", -(unsignedint)(void*) &a.c1-(unsignedint)(void*) &A, the(unsignedint)(void*) &a.s-(unsignedint)(void*) &A, -(unsignedint)(void*) &AMP;A.C2-(unsignedint)(void*) &A,Wuyi(unsignedint)(void*) &AMP;A.I-(unsignedint)(void*) &a); the  -printf"struct Bar C1%p, C2%p, S%p, I%p\n", Wu(unsignedint)(void*) &b.c1-(unsignedint)(void*) &B, -(unsignedint)(void*) &AMP;B.C2-(unsignedint)(void*) &B, About(unsignedint)(void*) &AMP;B.S-(unsignedint)(void*) &B, $(unsignedint)(void*) &AMP;B.I-(unsignedint)(void*) &b); -  -printf"struct Foo_pack C1%p, S%p, C2%p, I%p\n", -(unsignedint)(void*) &p.c1-(unsignedint)(void*) &p, A(unsignedint)(void*) &p.s-(unsignedint)(void*) &p, +(unsignedint)(void*) &AMP;P.C2-(unsignedint)(void*) &p, the(unsignedint)(void*) &AMP;P.I-(unsignedint)(void*) &p); -  $printf"sizeof Foo is%d\n",sizeof(foo)); theprintf"sizeof Bar is%d\n",sizeof(bar)); theprintf"sizeof Foo_pack is%d\n",sizeof(Foo_pack)); the      the     return 0; -  in  the}

Memory alignment issues and pragma pack commands in C/

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.