【问题标题】:Struct one-byte alignment conflicted with alignment requirement of the architecture?结构一字节对齐与架构的对齐要求冲突?
【发布时间】:2012-12-04 02:41:29
【问题描述】:

我之前发布了一个关于指针转换期间对齐访问的问题here。总而言之,最好不要使用未对齐访问来实现完全可移植,因为某些架构可能会抛出异常,或者与对齐访问相比,性能可能会变得非常慢。

但是,there are cases 我想使用单字节对齐,例如,在传输网络数据期间,我不想在结构中添加额外的填充。所以通常这里做的是:

#pragma pack (push, 1)
struct tTelegram
{
   u8 cmd;
   u8 index;
   u16 addr1_16;
   u16 addr2_16;
   u8  length_low;
   u8 data[1];
};
#pragma pack (pop)

那么您可能已经知道我的问题:如果我在结构上强制执行单字节对齐,这是否意味着它不能完全可移植,因为结构成员没有对齐?如果我既想要无填充又想要可移植性怎么办?

【问题讨论】:

  • 位域不可移植。 length_highreservednext 的打包顺序绝对取决于实现,不同的编译器以不同的方式执行。
  • 哦,是的!我只是从旧代码中复制了它。现在算了吧,我会删除它以专注于问题
  • @Dietrich,还是谢谢你:)
  • stackoverflow.com/questions/7793511/… 上的一些有用信息

标签: c++ c alignment


【解决方案1】:

首先,未对齐的内存访问是指跨越内存中多个字的单个数据。例如:在 32 位系统上,地址 0、4、8 等处的 32 位 int 对齐,但地址 1、2、3、5、6、7、9 等处将未对齐。

其次,未对齐的数据不会在 C++ 意义上“引发异常”,但可能会在 CPU 级别引发中断/陷阱/异常 - 例如UNIX 上的 SIGBUS,您通常会设置一个信号处理程序来对此做出反应,但是如果您需要以可移植的方式解析未对齐的数据,您不会通过捕获信号来执行此操作 - 您需要手动编写打包步骤和解压跨越字边界的数据。

在您的tTelegram 结构中,数据没有“未对齐”,但在从寄存器打包/解包数据时,移位和屏蔽数据的过程仍然可能比使用数据更慢 - 需要更多机器代码指令占据一个独立的词。

关于可移植性 - 所有非玩具编译器都可以选择按照您描述的方式打包,但确切的编译指示会有所不同,多字节值中的字节布局可能仍然是大端或小端 -字节序(或者一些很奇怪的东西),而一些 CPU 允许一些未对齐的数据访问(例如 x86),而另一些则不允许(例如 Ultrasparc)。

【讨论】:

  • 对于 CPU 不允许未对齐的数据访问,该架构的大多数编译器会通过多次访问对齐的内存地址“反汇编”数据来“欺骗”CPU,然后以某种方式对它们进行 OR-ed .对吗?
  • @EricZ:考虑一个紧凑的struct X { char x; int y; };。假设X 本身在字边界上对齐(编译器倾向于处理这一点),并且int 是字大小,那么y 数据成员必须是未对齐的。编译器可以看到并且应该生成位移和与(读取)/或(设置)y 的值。编译器不倾向于防止由未对齐指针(如*(int*)(1))引起的未对齐数据访问;在那种情况下,像 x86 这样的 CPU 会“捏造”(可能比正常的int 访问更慢),而其他像 Ultrasparcs 这样的 CPU 会陷入困境。
【解决方案2】:

在不同计算机之间传输数据时,您总是希望格式化数据。请注意,数据格式不一定是可读的,但它很可能是二进制的。二进制格式将包括每个数据项的确切位置、其类型、对于多字节数据、字节出现的顺序、大小或确定大小的方法等。不使用定义的格式会咬人,可能早于稍后。

换一种说法,虽然我见过你描述的方法,但我不认为它们是正常的,当涉及到不同实体之间定义的格式时,它们肯定是不正常的(当然,公司,可能也在不同部门和/或组)。在我为接收和发送数据工作的地方,肯定定义了确切的格式。如果定义的格式可以与struct 中的数据布局相匹配,它当然也用于解码数据,但众所周知它不是可移植的,并且旨在可移植的代码不会尝试使用这样的工具。相反,它使用读/写相关记录并适当地解码/编码不同的东西。通常,解码/编码代码是从某种描述确切数据布局的元格式生成的。

【讨论】:

  • 布局由一些工业协议很好地定义,所以我无事可做。你的观点是使用一字节对齐不便携?
  • 确实,字节对齐是不可移植的。并非所有编译器都支持强制字节对齐的选项。一个单词中的字节顺序也不总是相同的(Big Endian vs. Little Endian)。
  • +1 @Er​​icZ 除其他外,不,它不可移植。打包和对齐完全取决于平台,即使您的平台“允许”您在其中指定条件编译,根据定义它也不是可移植的。使其可移植的唯一保证方法是通过 双方 双方都遵循 严格protocol 定义,从字面上看,一直到单个八位字节。当它在 big-endian、little-endian、恶劣的对齐环境 (SPARC) 等环境中运行并且仍然工作时,您可能*会有所收获。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-07-18
  • 2016-02-23
  • 1970-01-01
  • 2017-07-28
  • 2011-06-20
相关资源
最近更新 更多