天天看点

内存对齐及#pragma pack的使用

在缺省情况下,C编译器为每一个变量或是数据单元按其自然对界条件分配空间。

在结构中,编译器为结构的每个成员按其自然对界(alignment)条件分配空间。各个成员按照它们被声明的顺序在内存中顺序存储(成员之间可能有插入的空字节),第一个成员的地址和整个结构的地址相同。

C编译器缺省的结构成员自然对界条件为“N字节对齐”,N即该成员数据类型的长度。如int型成员的自然对界条件为4字节对齐,而double类型的结构成员的自然对界条件为8字节对齐。若该成员的起始偏移不位于该成员的“默认自然对界条件”上,则在前一个节面后面添加适当个数的空字节。

C编译器缺省的结构整体的自然对界条件为:该结构所有成员中要求的最大自然对界条件。若结构体各成员长度之和不为“结构整体自然对界条件的整数倍,则在最后一个成员后填充空字节。

例子1(分析结构各成员的默认字节对界条界条件和结构整体的默认字节对界条件):

struct

Test

{

char

x1;

//

成员x1为char型(其起始地址必须1字节对界),其偏移地址为0

char

x2;

//

成员x2为char型(其起始地址必须1字节对界,其偏移地址为1

float

x3;

//

成员x3为float型(其起始地址必须4字节对界),编译器在x2和x3之间填充了两个空字节,其偏移地址为4

char

x4;

//

成员x4为char型(其起始地址必须1字节对界),其偏移地址为8

};

内存对齐及#pragma pack的使用

因为Test结构体中,最大的成员为flaot x3,因些此结构体的自然对界条件为4字节对齐。则结构体长度就为12字节,内存布局为1100 1111 1000。

例子2:

#include

<

stdio.h

>

//

#pragma pack(2)

typedef

struct

{

int

aa1;

//

4个字节对齐 1111

char

bb1;

//

1个字节对齐 1

short

cc1;

//

2个字节对齐 011

char

dd1;

//

1个字节对齐 1

} testlength1;

int

length1

=

sizeof

(testlength1);

//

4个字节对齐,占用字节1111 1011 1000,length = 12

typedef

struct

{

char

bb2;

//

1个字节对齐 1

int

aa2;

//

4个字节对齐 0001111

short

cc2;

//

2个字节对齐 11

char

dd2;

//

1个字节对齐 10

} testlength2;

int

length2

=

sizeof

(testlength2);

//

4个字节对齐,占用字节1000 1111 1100,length = 12

typedef

struct

{

char

bb3;

//

1个字节对齐 1

char

dd3;

//

1个字节对齐 1

int

aa3;

//

4个字节对齐 001111

short

cc23

//

2个字节对齐 11

} testlength3;

int

length3

=

sizeof

(testlength3);

//

4个字节对齐,占用字节1100 1111 1100,length = 12

typedef

struct

{

char

bb4;

//

1个字节对齐 1

char

dd4;

//

1个字节对齐 1

short

cc4;

//

2个字节对齐 11

int

aa4;

//

4个字节对齐 1111

} testlength4;

int

length4

=

sizeof

(testlength4);

//

4个字节对齐,占用字节1111 1111,length = 8

int

main(

void

)

{

printf(

"

length1 = %d.\n

"

,length1);

printf(

"

length2 = %d.\n

"

,length2);

printf(

"

length3 = %d.\n

"

,length3);

printf(

"

length4 = %d.\n

"

,length4);

return

;

}

改变缺省的对界条件(指定对界)

· 使用伪指令#pragma pack (n),C编译器将按照n个字节对齐。

· 使用伪指令#pragma pack (),取消自定义字节对齐方式。

这时,对齐规则为:

、数据成员对齐规则:结构(struct)(或联合(union))的数据成员,第一个数据成员放在offset为0的地方,以后每个数据成员的对齐按照#pragma pack指定的数值和这个数据成员自身长度中,比较小的那个进行。

2、结构(或联合)的整体对齐规则:在数据成员完成各自对齐之后,结构(或联合)本身也要进行对齐,对齐将按照#pragma pack指定的数值和结构(或联合)最大数据成员长度中,比较小的那个进行。

结合1、2推断:当#pragma pack的n值等于或超过所有数据成员长度的时候,这个n值的大小将不产生任何效果。

因此,当使用伪指令#pragma pack (2)时,Test结构体的大小为8,内存布局为11 11 11 10。

需要注意一点,当结构体中包含一个子结构体时,子结构中的成员按照#pragma pack指定的数值和子结构最大数据成员长度中,比较小的那个进行进行对齐。例子如下:

#pragma pack(8)

struct s1{

short a;

long b;

};

struct s2{

char c;

s1 d;

long long e;

};

#pragma pack()

sizeof(s2)的结果为24。S1的内存布局为1100 1111,S2的内存布局为1000 1100 1111 0000 1111 1111。

例子:

#include

<

stdio.h

>

#pragma

pack(2)

typedef

struct

{

int

aa1;

//

2个字节对齐 1111

char

bb1;

//

1个字节对齐 1

short

cc1;

//

2个字节对齐 011

char

dd1;

//

1个字节对齐 1

} testlength1;

int

length1

=

sizeof

(testlength1);

//

2个字节对齐,占用字节11 11 10 11 10,length = 10

typedef

struct

{

char

bb2;

//

1个字节对齐 1

int

aa2;

//

2个字节对齐 01111

short

cc2;

//

2个字节对齐 11

char

dd2;

//

1个字节对齐 1

} testlength2;

int

length2

=

sizeof

(testlength2);

//

2个字节对齐,占用字节10 11 11 11 10,length = 10

typedef

struct

{

char

bb3;

//

1个字节对齐 1

char

dd3;

//

1个字节对齐 1

int

aa3;

//

2个字节对齐 11 11

short

cc23

//

2个字节对齐 11

} testlength3;

int

length3

=

sizeof

(testlength3);

//

2个字节对齐,占用字节11 11 11 11,length = 8

typedef

struct

{

char

bb4;

//

1个字节对齐 1

char

dd4;

//

1个字节对齐 1

short

cc4;

//

2个字节对齐 11

int

aa4;

//

2个字节对齐 11 11

} testlength4;

int

length4

=

sizeof

(testlength4);

//

2个字节对齐,占用字节11 11 11 11,length = 8

int

main(

void

)

{

printf(

"

length1 = %d.\n

"

,length1);

printf(

"

length2 = %d.\n

"

,length2);

printf(

"

length3 = %d.\n

"

,length3);

printf(

"

length4 = %d.\n

"

,length4);

return

;

}

另外,还有如下的一种方式: