我想知道是否有人可以向我解释一下#pragma包预处理器语句是做什么的,更重要的是,为什么人们想要使用它。
我查看了MSDN页面,它提供了一些见解,但我希望从有经验的人那里听到更多。我以前在代码中见过它,尽管我似乎再也找不到在哪里了。
我想知道是否有人可以向我解释一下#pragma包预处理器语句是做什么的,更重要的是,为什么人们想要使用它。
我查看了MSDN页面,它提供了一些见解,但我希望从有经验的人那里听到更多。我以前在代码中见过它,尽管我似乎再也找不到在哪里了。
当前回答
I've used it in code before, though only to interface with legacy code. This was a Mac OS X Cocoa application that needed to load preference files from an earlier, Carbon version (which was itself backwards-compatible with the original M68k System 6.5 version...you get the idea). The preference files in the original version were a binary dump of a configuration structure, that used the #pragma pack(1) to avoid taking up extra space and saving junk (i.e. the padding bytes that would otherwise be in the structure).
代码的原始作者还使用#pragma pack(1)来存储在进程间通信中用作消息的结构。我认为这里的原因是为了避免未知或更改填充大小的可能性,因为代码有时会通过从开始计算字节数来查看消息结构的特定部分(ewww)。
其他回答
为什么要使用它?
减少结构的内存
为什么不应该使用它?
这可能会导致性能损失,因为某些系统在对齐的数据上工作得更好 一些机器将无法读取未对齐的数据 代码不可移植
#pragma pack指示编译器以特定的对齐方式打包结构成员。在声明结构体时,大多数编译器都会在成员之间插入填充,以确保它们与内存中适当的地址对齐(通常是类型大小的倍数)。这避免了在某些架构上与未正确对齐的访问变量相关的性能损失(或完全错误)。例如,给定4字节整数和以下结构体:
struct Test
{
char AA;
int BB;
char CC;
};
编译器可以选择像这样在内存中布局结构:
| 1 | 2 | 3 | 4 |
| AA(1) | pad.................. |
| BB(1) | BB(2) | BB(3) | BB(4) |
| CC(1) | pad.................. |
sizeof(Test)将是4 × 3 = 12,即使它只包含6个字节的数据。#pragma(据我所知)最常见的用例是在使用硬件设备时,需要确保编译器不会在数据中插入填充,并且每个成员都遵循前一个。使用#pragma pack(1),上面的结构体将像这样布局:
| 1 |
| AA(1) |
| BB(1) |
| BB(2) |
| BB(3) |
| BB(4) |
| CC(1) |
sizeof(Test)是1 × 6 = 6。
使用#pragma pack(2),上面的结构体将像这样布局:
| 1 | 2 |
| AA(1) | pad.. |
| BB(1) | BB(2) |
| BB(3) | BB(4) |
| CC(1) | pad.. |
sizeof(Test)是2 × 4 = 8。
struct中变量的顺序也很重要。变量顺序如下:
struct Test
{
char AA;
char CC;
int BB;
};
使用#pragma pack(2),结构体将像这样布局:
| 1 | 2 |
| AA(1) | CC(1) |
| BB(1) | BB(2) |
| BB(3) | BB(4) |
sizeOf(Test)为3 × 2 = 6。
数据元素(例如类和结构的成员)通常在当前一代处理器的WORD或DWORD边界上对齐,以提高访问时间。在32位处理器上,在不能被4整除的地址处检索DWORD至少需要一个额外的CPU周期。如果你有三个char成员char a b c;,它们实际上会占用6到12个字节的存储空间。
#pragma允许你覆盖这个,以实现更有效的空间使用,以访问速度为代价,或为了不同编译器目标之间存储的数据的一致性。从16位代码到32位代码的转换给我带来了很多乐趣;我预计移植到64位代码也会对某些代码造成同样的困扰。
编译器可以对结构中的成员进行对齐,以在特定平台上实现最大性能。#pragma包指令允许你控制对齐方式。通常,您应该将其保留为默认值以获得最佳性能。如果你需要传递一个结构到远程机器,你通常会使用#pragma pack 1来排除任何不需要的对齐。
#pragma用于向编译器发送不可移植(仅在此编译器中)消息。像禁用某些警告和包装结构是常见的原因。如果在编译时将警告作为错误标志打开,则禁用特定警告特别有用。
#pragma pack特别用于指示被打包的结构体不应该让其成员对齐。当您有一个内存映射接口到某个硬件,并且需要能够准确控制不同结构成员指向的位置时,它非常有用。这显然不是一个很好的速度优化,因为大多数机器在处理对齐数据时要快得多。
使用#pragma pack(push,1)和#pragma pack(pop)来撤销换行