Cen*_*noc 212 c c-preprocessor pragma-pack
我想知道是否有人可以向我解释#pragma pack预处理器语句的作用,更重要的是,为什么人们会想要使用它.
我查看了MSDN页面,它提供了一些见解,但我希望能从有经验的人那里听到更多.我以前在代码中看过它,虽然我似乎无法找到它的位置.
Nic*_*yer 390
#pragma pack指示编译器打包具有特定对齐的结构成员.大多数编译器在声明结构时会在成员之间插入填充,以确保它们与内存中的适当地址对齐(通常是类型大小的倍数).这避免了与访问未正确对齐的变量相关联的某些体系结构上的性能损失(或彻底错误).例如,给定4字节整数和以下结构:
struct Test
{
char AA;
int BB;
char CC;
};
Run Code Online (Sandbox Code Playgroud)
编译器可以选择将结构放在内存中,如下所示:
| 1 | 2 | 3 | 4 |
| AA(1) | pad.................. |
| BB(1) | BB(2) | BB(3) | BB(4) |
| CC(1) | pad.................. |
Run Code Online (Sandbox Code Playgroud)
并且sizeof(Test)将是4×3 = 12,即使它只包含6个字节的数据.#pragma(据我所知)最常见的用例是在使用硬件设备时,您需要确保编译器不会在数据中插入填充,并且每个成员都遵循前一个成员.有了#pragma pack(1),上面的结构将如下布局:
| 1 |
| AA(1) |
| BB(1) |
| BB(2) |
| BB(3) |
| BB(4) |
| CC(1) |
Run Code Online (Sandbox Code Playgroud)
并且sizeof(Test)将是1×6 = 6.
有了#pragma pack(2),上面的结构将如下布局:
| 1 | 2 |
| AA(1) | pad.. |
| BB(1) | BB(2) |
| BB(3) | BB(4) |
| CC(1) | pad.. |
Run Code Online (Sandbox Code Playgroud)
并且sizeof(Test)将是2×4 = 8.
nmi*_*els 24
#pragma用于将非可移植(如在此编译器中)消息发送到编译器.禁用某些警告和打包结构的事情是常见的原因.如果在警告启用错误标志的情况下进行编译,则禁用特定警告特别有用.
#pragma pack特别用于表示正在打包的结构不应该使其成员对齐.当你有一个硬件的内存映射接口并且需要能够精确控制不同结构成员指向的位置时,它很有用.这显然不是一个好的速度优化,因为大多数机器在处理对齐数据方面要快得多.
Jer*_*fin 15
它告诉编译器将结构中的对象对齐的边界.例如,如果我有类似的东西:
struct foo {
char a;
int b;
};
Run Code Online (Sandbox Code Playgroud)
对于典型的32位机器,您通常"希望"在其间有3个字节的填充a,b因此b将落在4字节边界以最大化其访问速度(这是默认情况下通常会发生的情况).
但是,如果必须匹配外部定义的结构,则需要确保编译器完全根据外部定义布局结构.在这种情况下,你可以给编译器一个#pragma pack(1)告诉它不要在成员之间插入任何填充 - 如果结构的定义包括成员之间的填充,你明确地插入它(例如,通常与成员命名unusedN或ignoreN,或在其上的东西订购).
数据元素(例如,类和结构的成员)通常在当前生成处理器的WORD或DWORD边界上对齐,以便改善访问时间.在不能被4整除的地址处检索DWORD需要在32位处理器上至少有一个额外的CPU周期.因此,如果您有三个char成员char a, b, c;,他们实际上倾向于占用6或12个字节的存储空间.
#pragma允许您覆盖它以实现更高效的空间使用,代价是访问速度,或者是为了保持不同编译器目标之间存储数据的一致性.从16位代码转换为32位代码,我感到非常有趣.我希望移植到64位代码会导致某些代码出现同样的问题.