什么时候不应该使用#pragma pack?

时间:2011-10-19 14:24:59

标签: c structure

在C中,当我们使用结构时,何时使用 #pragma pack 指令是不合适的??

问题的补充......

有人可以解释更多关于如何使用指针访问未对齐数据失败的问题吗?

5 个答案:

答案 0 :(得分:37)

此处是固件开发人员。 #pragma pack是非常熟悉的领域。我会解释一下。

一般来说,不应使用#pragma pack。是的,它会使你的结构在内存中变小,因为它消除了struct成员之间的所有填充。但它可以使 访问 这些成员更加昂贵,因为成员可能不再符合他们的要求。例如,在ARM体系结构中,4字节整数通常需要4字节对齐,但在压缩结构中它们可能不是。这意味着编译器需要添加额外的指令来安全地访问该struct成员,或者开发人员必须逐个字节地访问它并手动重建int。无论哪种方式,它都会产生比对齐访问更多的代码,因此您的结构最终变小,但您的访问代码可能会变得越来越慢。

当您的结构必须与完全数据布局匹配时,使用#pragma pack。当您编写匹配数据传输或访问规范的代码时,通常会发生这种情况...例如,网络协议,存储协议,访问HW寄存器的设备驱动程序。在这些情况下,您可能需要#pragma pack来强制您的结构与规范定义的数据布局相匹配。这可能会导致前一段中提到的性能损失相同,但可能是遵守规范的唯一方法。

答案 1 :(得分:3)

我会说除非有充分的理由这样做,否则你不应该打包。

指定pack时,将删除所有填充。因此,结构成员可能是未对齐的 - 这可能会产生性能影响。

答案 2 :(得分:1)

在大多数架构中,底层访问必须与访问数据的对齐匹配。

这意味着,如果您有32位值,则可以有效地访问它,如果它存储在可分为4的地址中。

如果使用#pragma pack,变量的位置可以是任何内容,编译器必须逐个访问元素并将它们组合在一起。具体来说,下面是生成的代码,用于读取V850E(嵌入式世界中流行的微控制器)上的正常int

LD.W        a[zero],r5

相应地,以下是访问压缩结构中int的代码:

LD.BU       g+3[zero],r1
SHL         8,r1
LD.BU       g+2[zero],r6
OR          r1,r6
SHL         8,r6
LD.BU       g+1[zero],r7
OR          r6,r7
SHL         8,r7
LD.BU       g[zero],r1
OR          r7,r1

不使用压缩结构的另一个原因是,除非体系结构支持未对齐的指针访问,否则无法取消引用指向压缩结构体成员的指针。原因是该点的类型将是一个普通的int指针,并且编译器不知道它必须访问它指向的任何内容。

我强烈建议您不要使用'#pragma pack',除非绝对必要。如果您可以控制结构定义,那么有一些技术可以确保结构布局是无填充的。如果没有,更好的方法是将任何未对齐的数据复制到新的对齐的结构中,并在您的应用程序中使用它。

答案 3 :(得分:1)

#pragma pack指令提供了满足此要求的方法。该指令指定结构成员的包装对齐。在看到pragma之后,pragma在第一个结构声明生效。 Turbo C / C ++编译器不支持此功能,VC ++编译器也支持此功能。

答案 4 :(得分:0)

你永远不应该使用#pragma pack或类似的。它总是会导致危险的可移植性问题。例如,考虑结构:

struct foo {
    char a;
    int b;
} bar;

并致电scanf("%d", &bar.b)。在没有错位访问的计算机上,这将导致scanf 内部的错误(或损坏内存!)!这是因为&bar.b实际上并不是有效的int * - 它是未对齐的,但它传递给它的代码无法知道并解决它,就像你编写的那样{{1} }。

打包结构的唯一预期用途是序列化,但这也会导致不可移植的文件。您应该只编写正确的序列化函数。