# C语言结构体中的数据对齐

C++实验课的时候，坐在我旁边的同学问了我一个问题：

struct

{

char a;

int b;

double c;

} sa;

struct

{

int a;

char b;

} sa;

struct

{

int a;

char b;

double c;

} sb;

struct

{

int a;

double c;

char b;

} sc;

struct

{

int a;

char b, c, d, e,;

} sa1;

struct

{

int a;

char b;

int c;

} sa2;

sb中的int a 4个字节，紧接着的char b占用1个字节，但是char b随后的double c需要占用8个字节，所以char bdouble c不能挤在一个4个字节的单位里面。于是在char bdouble c之间填了3个字节的空位，实现与其后的数据的对齐，这样就不难理解为什么sizeof(sa1)=8了。

sbsc的唯一区别就是char bdouble c的定义次序颠倒了，结果使得sizeof(sb)sizeof(sc)产生了差别。能想到的唯一解释是sbsc的对齐的最小单位不一样了。于是我又设计了一组对比：

struct

{

int a;

int d;

double c;

char b;

} sc1;

struct

{

int a;

double c;

} sc2;

sc1sc的基础上在int a后面紧接着加上了int d;但是结果sizeof(sc1)=24= sizeof(sc)，这说明在int a的后面存在4个字节的空位。看来这次系统给结构体内的变量分配空间的时候，不再像sa那样以4个字节为一组了。

1、在程序内部用#pragma pack(n)指定

#pragma pack(1)可以使编译器不在struct内留空位。

2、  用编译指令

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;

}

struct    // packing is 8

{

int a;

char b;

} sa;

struct    // packing is 8

{

int a;

int c;

char b;

} sa;

packing值小于结构体内占用空间最多成员占用的字节数的时候，以packing值为准。

#pragma pack(push,1) // packing is now 1

struct

{

int a;

char b;

double c;

} sb;

#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 is seen; the pragma has no effect on definitions.

When you use #pragma pack(n), where n is 1, 2, 4, 8, or 16, each structure member after the first is stored on the smaller member type or n-byte boundaries. If you use #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 ] )

This syntax allows you to combine program components into a single translation unit if the different components use pack pragmas to specify different packing alignments.

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 identifier is 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 and after the header file is encountered:

/* File name: include1.h
*/
#pragma pack( push, enter_include1 )
/* Your include-file code ... */
#pragma pack( pop, enter_include1 )
/* End of include1.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 enter_include1. The header file thus ensures that the pack value is the same before and after 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 "include1.h"
#pragma pack( pop, before_include1 )

In the previous example, your code is protected from any changes to the packing value that might occur in include.h.

• 本文已收录于以下专栏：

举报原因： 您举报文章：C语言结构体中的数据对齐 色情 政治 抄袭 广告 招聘 骂人 其他 (最多只允许输入30个字)