#pragma pack() 释疑

1.#pragma简述

在所有的预处理指令中,#Pragma 指令可能是最复杂的了,它的作用是设定编译器的状态或者是指示编译器完成一些特定的动作。#pragma 指令对每个编译器给出了一个方法,在保持与 C 和 C++ 语言完全兼容的情况下,给出主机或操作系统专有的特征。依据定义,编译指示是机器或操作系统专有的,且对于每个编译器都是不同的。

2.#pragma pack的作用

#pragma pack主要作用就是改变编译器的内存对齐方式,这个指令在网络报文的处理中有着重要的作用,#pragma pack(n) 是最基本的用法,其作用是改变编译器的对齐方式, 不使用这条指令的情况下,编译器默认采取 #pragma pack(8) 也就是 8 字节的默认对齐方式,n 值可以取(1, 2, 4, 8, 16) 中任意一值。

3.#pragma pack详细介绍

3.1 #pragma pack(show)

#pragma pack(show) 显示当前内存对齐的字节数。也就是packing aligment

#pragma pack(show)  // 默认内存对齐的值为 8

int main()
{
	...
}

在程序中 #pragma pack(show) 会在编译阶段提出一个警告,说明当前对齐字节数。

3.2 #pragma pack(push [, identifier] [, n])

单纯使用 #pragma pack(push) 会将当前的对齐字节数压入栈顶,并设置这个值为新的对齐字节数, 就是说不会改变这个值。而使用 #pragma pack(push, n) 会将当前的对齐字节数压入栈顶,并设置 n 为新的对齐字节数。

再就是这个 #pragma pack(push, identifier [, n]) 会在上面的操作基础上为这个对齐字节数附上一个标识符,这里注意这个标识符只能以($_字母)开始, 标识符中可以有($_字母数字),并且标识符不能是关键字(pushpop可以作为标识符)。这个标识符的作用我会在 pop 中详细介绍。

push 的使用:

#pragma pack(push, 4)
#pragma pack(show)  // 内存对齐字节数为 4

#pragma pack(push)
#pragma pack(show)  // 内存对齐字节数为 4

int  main()
{
    ...
}

3.3 #pragma pack(pop [, identifier] [, n])

同样单纯使用 #pragma pack(pop) 会弹出栈顶对齐字节数,并设置其为新的内存对齐字节数。

#pragma pack(push, 4)
#pragma pack(show)  // 内存对齐字节数为 4

#pragma pack(pop)
#pragma pack(show)  // 内存对齐字节数为 8

int main()
{
	...
}

使用 #pragma pack(pop, n) 情况就不同了,它会弹出栈顶并直接丢弃,设置 n 为其新的内存对齐字节数。

#pragma pack(push, 4)
#pragma pack(push, 4)
#pragma pack(show)  // 内存对齐数为 4

#pragma pack(pop, 16)
#pragma pack(show)  // 内存对齐数为 16

#pragma pack(pop)
#pragma pack(show)  // 内存对齐数为 8

int main()
{
	...
}

#pragma pack(pop, identifier [, n]) 较为复杂,编译器执行这条执行时会从栈顶向下顺序查找匹配的identifier,找到 identifier 相同的这个数之后将从栈顶到 identifier,包括找到 identifier 全部 pop 弹出, 若没有找到则不进行任何操作。

#pragma pack(push, a, 4)
#pragma pack(push, b, 1)
#pragma pack(push, c, 16)
#pragma pack(push, 2)
#pragma pack(push, 1)
#pragma pack(pop)
#pragma pack(show)  // 内存对齐数为 2

#pragma pack(pop, c)
#pragma pack(show)  // 内存对齐数为 1

#pragma pack(pop, a)
#pragma pack(show)  // 内存对齐数为 8

int main()
{
	...
}

由于前面提到的 pushpop 也可以作为关键字所以可以设计出很有戏剧效果的预处理头:

#pragma pack(push, push, 4)
#pragma pack(push, pop, 16)
#pragma pack(push, push, 8)
#pragma pack(push, push, 16)
#pragma pack(pop, pop)
#pragma pack(show)  // 内存对齐数为 4

int main()
{
	...
}

4. 示例

#pragma pack(show)  // 默认内存对其按照8个字节,==8
#pragma pack(4)  // 将8个字节对齐改成了4个字节
#pragma pack(show)  // ==4

typedef struct {
    uint32_t iDeviceType;                          // see above defines
    char     szPath[512];                          // device path to use in FZ_Open
    char     szShortName[32];                      // a more user friendly name
    char     szSerial[16];                         // device serial number
    uint32_t iReserved[64];
} FZ_DEVICE_INFO;

#pragma pack(show)  // ==4,没有发生改变
#pragma pack()  // 将内存对齐设置变成默认的8个字节
#pragma pack(show)  // ==8

参考文档

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值