如题
首先给出一段之前测试的代码
#include<stdio.h>
#pragma pack (4)
typedef struct a
{
int b; //4
char c; //1
short d;//2
float e;//4
char f; //1
} st;
int main()
{
st s;
printf("%d\n",sizeof(s));
printf("str s: %p\n",&s);
printf("int b: %p\n",&(s.b));
printf("char c: %p\n",&(s.c));
printf("short d: %p\n",&(s.d));
printf("float e: %p\n",&(s.e));
printf("char f: %p\n",&(s.f));
return 0;
}
原来理解为:为每个数据成员分配的内存大小都没4个字节,不足的补0,实际是一种误解。
实际结果为:
16
str s: 0022FEE0
int b: 0022FEE0
char c: 0022FEE4
short d: 0022FEE6
float e: 0022FEE8
char f: 0022FEEC
内存分配为 1111_10_11_1111_1000 16byte
改变程序代码为#pragma pack (8) :
#include<stdio.h>
#pragma pack (8)
typedef struct a
{
int b; //4
char c; //1
short d;//2
float e;//4
char f; //1
} st;
int main()
{
st s;
printf("%d\n",sizeof(s));
printf("str s: %p\n",&s);
printf("int b: %p\n",&(s.b));
printf("char c: %p\n",&(s.c));
printf("short d: %p\n",&(s.d));
printf("float e: %p\n",&(s.e));
printf("char f: %p\n",&(s.f));
return 0;
}
运行结果是一致的;
16
str s: 0022FEE0
int b: 0022FEE0
char c: 0022FEE4
short d: 0022FEE6
float e: 0022FEE8
char f: 0022FEEC
改变程序代码为#pragma pack (2) :
#include<stdio.h>
#pragma pack (2)
typedef struct a
{
int b; //4
char c; //1
short d;//2
float e;//4
char f; //1
} st;
int main()
{
st s;
printf("%d\n",sizeof(s));
printf("str s: %p\n",&s);
printf("int b: %p\n",&(s.b));
printf("char c: %p\n",&(s.c));
printf("short d: %p\n",&(s.d));
printf("float e: %p\n",&(s.e));
printf("char f: %p\n",&(s.f));
return 0;
}
运行结果为:
14
str s: 0022FEE2
int b: 0022FEE2
char c: 0022FEE6
short d: 0022FEE8
float e: 0022FEEA
char f: 0022FEEE
发生了改变,存储为 1111_10_11_1111_10 14byte
-------------------------------------------------------------分析----------------------------------------------------------- -----------------------------------------------------
#pragma pack ()的对其原则:
1、数据成员对齐规则:结构(struct)(或联合(union))的数据成员,第一个数据成员放在offset为0的地方,以后每个数据成员的对齐按照
#pragma pack指定的数值和这个数据成员自身长度中,比较小的那个进行。
2、结构(或联合)的整体对齐规则:在数据成员完成各自对齐之后,结构(或联合)本身也要进行对齐,对齐将按照#pragma pack指定的数值和结构
(或联合)最大数据成员长度中,比较小的那个进行。
结合1、2推断:当#pragma pack的n值等于或超过所有数据成员长度的时候,这个n值的大小将不产生任何效果。
根据这个原则再分析一下前面的测试代码。
#pragma pack (2)
typedef struct a
{
int b; //int 4字节和2 取2个字节对齐 存储形式为 1111
char c; //char 1字节和2 取1个字节对齐 存储形式为 1
short d;//short 2个字节和2 取2个字节对齐 存储形式为 011
float e;//float 4个字节和2 取2个字节对齐 存储形式为 11_11
char f; //char 1个字节和2 取1个字节对齐 存储形式为 1
} st;
实际结构体内部的对齐方式 就是像上面写出的一样 1111 1011 1111 1 为13个字节
但是还有一个对齐及struct整体对齐,struct 最大成员字节为4 和2 取2个字节对齐 所以 最终为 1111 1011 1111 10 为14个字节
为了验证上面分析的正确性,再改变代码为1字节对齐,运行结果为:
12
str s: 0022FEE4
int b: 0022FEE4
char c: 0022FEE8
short d: 0022FEE9
float e: 0022FEEB
char f: 0022FEEF
1111_1_11_1111_1 12byte 成立
-----------------------------------------------------------------------------拓展-------------------------------------------------------------------------------
(1) MSDN中对于n的规定:
n(可选)指定要用于封装的值(以字节为单位)。 如果没有为模块设置编译器选项 /Zp,n 的默认值为 8。 有效值为 1、2、4、8 和 16。 成员将在作为 n 的倍数或成员的大小的倍数的边界(以较小者为准)上对齐。
(2) 还有一个关于struct中定义struct的例子可以看一下:
#pragma pack(8)
typedef struct s1{
short a;
long b;
} S1;
typedef struct s2{
char c;
S1 d;
long long e;
}S2;
#pragma pack()
s1 11_001111 8byte
s2 1_000000011001111_11111111 24byte