使用pragma pack(1)时是否存在性能问题?

Nic*_*las 13 c gcc

我们的头文件用于#pragma pack(1)大多数结构(用于网络和文件I/O).据我所知,它将结构的对齐方式从默认的8个字节更改为1个字节的对齐方式.

假设一切都在32位Linux(也许是Windows)中运行,那么这种打包对齐是否会带来任何性能损失?

我不关心库的可移植性,但更关注文件和网络I/O与不同#pragma包的兼容性以及性能问题.

Jos*_*ley 14

当字符对齐的内存地址发生时,内存访问速度最快.最简单的例子是以下结构(@Didier也使用):

struct sample {
   char a;
   int b;
};
Run Code Online (Sandbox Code Playgroud)

默认情况下,GCC插入填充,因此a位于偏移0处,b位于偏移4处(字对齐).没有填充,b不是字对齐的,访问速度较慢.

慢多少?

  • 对于32位x86,根据Intel 64和IA32架构软件开发人员手册:
    处理器需要两次内存访问才能进行未对齐的内存访问; 对齐访问只需要一次内存访问.跨越4字节边界的字或双字操作数或跨越8字节边界的四字操作数被认为是未对齐的,并且需要两个单独的存储器总线周期来进行访问.
    与大多数性能问题一样,您必须对应用程序进行基准测试,以了解这在实践中存在多少问题.
  • 根据维基百科,像SSE2这样的x86扩展需要字对齐.
  • 许多其他架构需要字对齐(如果数据结构不是字对齐的话,将产生SIGBUS错误).

关于可移植性:我假设您正在使用,#pragma pack(1)以便您可以通过电线和磁盘发送结构,而不必担心不同的编译器或平台打包结构.这是有效的,但是,要记住以下几个问题:

  • 这对于处理大端和小端问题没有任何作用.您可以通过在结构中的任何整数,无符号等上调用htons函数系列来处理这些问题.
  • 根据我的经验,在应用程序代码中使用打包的可序列化结构并不是很有趣.它们很难在不破坏向后兼容性的情况下进行修改和扩展,并且如前所述,存在性能损失.考虑将打包的,可序列化的结构体内容转移到等效的非打包的可扩展结构中进行处理,或考虑使用像Protocol Buffers(具有C绑定)这样的完整序列化库.


Did*_*set 6

是.绝对有.

例如,如果定义结构:

struct dumb {
    char c;
    int  i;
};
Run Code Online (Sandbox Code Playgroud)

然后无论何时访问成员i,CPU都会变慢,因为32位值i无法以原生的对齐方式访问.为简单起见,假设CPU必须从内存中获取3个字节,然后从下一个位置获取另外1个字节,以将值从内存传输到CPU寄存器.