我想知道是否有人可以向我解释一下#pragma包预处理器语句是做什么的,更重要的是,为什么人们想要使用它。

我查看了MSDN页面,它提供了一些见解,但我希望从有经验的人那里听到更多。我以前在代码中见过它,尽管我似乎再也找不到在哪里了。


当前回答

编译器可以对结构中的成员进行对齐,以在特定平台上实现最大性能。#pragma包指令允许你控制对齐方式。通常,您应该将其保留为默认值以获得最佳性能。如果你需要传递一个结构到远程机器,你通常会使用#pragma pack 1来排除任何不需要的对齐。

其他回答

数据元素(例如类和结构的成员)通常在当前一代处理器的WORD或DWORD边界上对齐,以提高访问时间。在32位处理器上,在不能被4整除的地址处检索DWORD至少需要一个额外的CPU周期。如果你有三个char成员char a b c;,它们实际上会占用6到12个字节的存储空间。

#pragma允许你覆盖这个,以实现更有效的空间使用,以访问速度为代价,或为了不同编译器目标之间存储的数据的一致性。从16位代码到32位代码的转换给我带来了很多乐趣;我预计移植到64位代码也会对某些代码造成同样的困扰。

编译器可以对结构中的成员进行对齐,以在特定平台上实现最大性能。#pragma包指令允许你控制对齐方式。通常,您应该将其保留为默认值以获得最佳性能。如果你需要传递一个结构到远程机器,你通常会使用#pragma pack 1来排除任何不需要的对齐。

我见过有人使用它来确保一个结构占用整个缓存行,以防止在多线程上下文中错误共享。如果你将有大量的对象,在默认情况下将它们松散地打包,它可以节省内存并提高缓存性能,尽管未对齐的内存访问通常会降低速度,所以可能会有一个缺点。

你可能只在对某些硬件(例如内存映射设备)编码时才会使用它,这些硬件对寄存器排序和对齐有严格的要求。

然而,这似乎是实现这一目标的一个相当生硬的工具。一个更好的方法是在汇编程序中编写一个迷你驱动程序,并给它一个C调用接口,而不是摸索这个pragma。

请注意,#pragma pack提供了其他实现数据一致性的方法(例如,有些人使用#pragma pack(1)来实现应该通过网络发送的结构)。例如,请参阅以下代码及其后续输出:

#include <stdio.h>

struct a {
    char one;
    char two[2];
    char eight[8];
    char four[4];
};

struct b { 
    char one;
    short two;
    long int eight;
    int four;
};

int main(int argc, char** argv) {
    struct a twoa[2] = {}; 
    struct b twob[2] = {}; 
    printf("sizeof(struct a): %i, sizeof(struct b): %i\n", sizeof(struct a), sizeof(struct b));
    printf("sizeof(twoa): %i, sizeof(twob): %i\n", sizeof(twoa), sizeof(twob));
}

回显如下: Sizeof (struct a): 15, Sizeof (struct b): 24 Sizeof (twoa): 30, Sizeof (twob): 48

注意结构体a的大小和字节数是一样的,但是结构体b添加了填充(关于填充的详细信息请参见此)。通过这样做,而不是#pragma包,你可以控制将“连线格式”转换为适当的类型。例如,“char 2[2]”转换为“short int”等等。