​​#pragma pack(push,1)与#pragma pack(1)的区别​​

这是给编译器用的参数设置(注意,在编译阶段),有关结构体字节对齐方式设置, #pragma pack是指定数据在内存中的对齐方式。

#pragma pack (n)             //作用:C编译器将按照n个字节对齐。
#pragma pack () // 作用:取消自定义字节对齐方式。


#pragma pack (push,1) //作用:是指把原来对齐方式设置压栈,并设新的对齐方式设置为1个字节对齐
#pragma pack(pop) // 作用:恢复对齐状态

因此可见,加入push和pop可以使对齐恢复到原来状态,而不是编译器默认,可以说后者更优,但是很多时候两者差别不大。

如果#pramga pack(n)中的n大于结构体成员中任何一个成员所占用的字节数,则该n值无效。编译器会选取结构体中最大数据成员的字节数为基准进行对齐。


结构体为什么默认对齐

在没有设置多少字节对齐的时候,结构体会默认选取结构体中最大数据成员的字节数为基础进行对齐。编译器为什么会耗费资源呢?

对齐的作用和原因:各个硬件平台对存储空间的处理上有很大的不同。一些平台对某些特定类型的数据只能从某些特定地址开始存取。比如有些架构的CPU在访问 一个没有进行对齐的变量的时候会发生错误,那么在这种架构下编程必须保证字节对齐.其他平台可能没有这种情况,但是最常见的是如果不按照适合其平台要求对 数据存放进行对齐,会在存取效率上带来损失。比如有些平台每次读都是从偶地址开始,如果一个int型(假设为32位系统)如果存放在偶地址开始的地方,那 么一个读周期就可以读出这32bit,而如果存放在奇地址开始的地方,就需要2个读周期,并对两次读出的结果的高低字节进行拼凑才能得到该32bit数 据。显然在读取效率上下降很多。另外一层原因是:某些硬件平台只能从规定的地址处取某些特定类型的数据,否则会抛出硬件异常。

为什么使用​​#pragma pack​​

上面说了那么多了,人家结构体会采用默认的对齐方式,以空间换取CPU的读取效率,那为啥我们还要去修改其对齐方式呢?

原因是:一节省空间,二在某些场合使结构体更易于控制。

应用实例:

在网络协议编程中,经常会处理不同协议的数据报文。一种方法是通过指针偏移的方法来得到各种信息,但这样做不仅编程复杂,而且一旦协议有变化,程序修改起来也比较麻烦。在了解了编译器对结构空间的分配原则之后,我们完全可以利用这一特性定义自己的协议结构,通过访问结构的成员来获取各种信息。这样做,不仅简化了编程,而且即使协议发生变化,我们也只需修改协议结构的定义即可,其它程序无需修改,省时省力。下面以TCP协议首部为例,说明如何定义协议结构。其协议结构定义如下:


以下是C/C++中不同数据类型所占用的内存的大小:

类型

32系统位(字节)

64位系统(字节)

char

1

1

int

4

大多数4,少数8

short

2

2

long

4

8

float

4

4

double

8

8

指针

4

8

结构体(struct)

对齐问题

对齐问题

联合体(union)

成员中最长的成员

成员中最长的成员

枚举(enum)

根据数据类型

根据数据类型

所以想判断当前系统是多少位的,最简单的做法就是看看指针占用几个字节。