在C中,当我们使用结构时,何时使用 #pragma pack 指令是不合适的??
问题的补充......
有人可以解释更多关于如何使用指针访问未对齐数据失败的问题吗?
答案 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} }。
打包结构的唯一预期用途是序列化,但这也会导致不可移植的文件。您应该只编写正确的序列化函数。