C ++中未对齐访问的正确性

从我读到的,错位的访问意味着大部分两件事:

  • 您可能会收到性能损失
  • 您将失去对齐访问所具有的加载和存储的原子性
  • 假设性能不是问题,我想从软件中得到的结果是正确的,访问失调有多糟? 我的理解是,x86 CPU将正确处理这些访问,但可能需要做额外的工作来获取数据。

    什么导致我问这个问题是用-fsanitize=undefined编译我的代码。 我有很多关于错位商店/货物的错误。 我不确定这是否是一个问题,因为:

  • 只有在数据准备过程中才会执行存储过程,这是一个单线程过程,所以我不关心原子性的损失
  • 加载是在一个多线程进程中执行的,在这个进程中很多线程(四个或更多)访问数据,但数据不会被任何一个修改(保存在const uint8_t*变量中)
  • 访问的原因不对齐的是const uint8_t*数组包含来自许多不同类型的字节( uint8_tuint16_tuint32_tuint64_tint64_t )。

    我确信没有负载超出了分配的uint8_t数组的范围(例如,程序不会从指向分配的内存块的最后一个,两个或三个字节的地址加载uint64_t ),并且确信我的访问是所有正确的 - 只有错位。

    我读到的另一件事是,这样的负载可能会打破严格的别名规则,但代码编译时没有使用-Wstrict-aliasing -Werror (我早已启用)的单个警告。

    我应该在uint8_t数组中填充数据以确保访问对齐,还是可以安全地忽略警告?


    有不支持未对齐访问的平台(您将会崩溃)。 而且,有些平台支持未对齐的访问,但有一些asm指令需要对齐访问。 例如,在ARM上,有LDRD指令,它需要对齐的内存地址。 不幸的是,编译器可以自由使用该指令。 但是,通常会有一个编译器扩展,告诉编译器该指针未对齐,因此不会使用LDRD。

    在支持UA的平台上,有您提到的处罚。

    我建议你使用memcpy 。 它适用于所有平台,编译器现在相当不错,可以优化它(所以你不会得到memcpy调用,但快速mov指令)。


    主要问题不是性能或原子性,而是正确性。 根据C和C ++标准,未对齐的访问会调用未定义的行为,因此您不能依赖任何特定的结果。 它可能工作,或者可能会崩溃。 或者它可能首先工作,并在稍后停止工作。 这是你得到的错误信息的本质。 如果您知道这些错误始终适用于您,您可以选择忽略这些错误,但由于您通过使用相应的编译器开关要求标记此类错误,所以您应该努力避免这些错误是合理的,特别是如果你并不确定你的代码会永远留在这个平台上。 此外,即使在同一个平台上,你怎么知道它总是适合你?

    从你写的内容来看,数据似乎是由同一台机器写入的,稍后读取数据,只有线程不同。 如果是这样,你应该尝试以正确对齐的方式写入数据,例如在适当的地方使用填充。 编译器可以通过将数据打包在正确定义的结构而非非结构化缓冲区中来获得帮助。 这也会给你更多的类型安全。

    否则,您将不得不担心的不仅仅是对齐。 例如,您还需要考虑端到端的问题。 在这种情况下,您可能正在编写一种外部数据记录,最终可能在另一台机器上。 您正在寻找一种机器中立的外部数据表示法,您可以自己定义,或者更好地使用为RPC发明的几种标准表示法之一,这种表示法的优点是可以找到用于读取和写入的库。

    链接地址: http://www.djcxy.com/p/54093.html

    上一篇: Correctness of misaligned access in C++

    下一篇: Where can I find what the alignment requirement for any arbitrary compiler?