您的位置:首页 > 其它

关于之前对#pragma pack ()误解的纠正

2014-09-29 15:18 204 查看
如题

首先给出一段之前测试的代码

#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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: