【发布时间】:2017-06-25 11:35:35
【问题描述】:
根据我的阅读,未对齐的访问主要意味着两件事:
- 您可能会出现性能损失
- 您将失去对齐访问所具有的加载和存储的原子性
假设性能不是问题,并且我希望从软件中获得正确性,那么未对齐的访问有多糟糕?我的理解是 x86 CPU 将正确处理此类访问,但可能需要做额外的工作来获取数据。
让我提出这个问题的原因是使用-fsanitize=undefined 编译我的代码。我收到了许多关于未对齐存储/加载的错误。我不确定这是否是个问题,因为:
- 存储仅在数据准备期间执行,这是一个单线程进程,因此我不担心原子性丢失
- 加载在多线程进程中执行,其中许多线程(四个或更多)访问数据,但数据不会被任何线程修改(保存在
const uint8_t*变量中)
访问未对齐的原因是 const uint8_t* 数组包含来自许多不同类型的字节(uint8_t、uint16_t、uint32_t、uint64_t 和 int64_t)。
我确信没有负载超出分配的uint8_t 数组的范围(例如,程序永远不会从指向已分配内存块的最后一个、两个或三个字节的地址加载uint64_t),并且确信我的访问都是正确的 - 只是未对齐。
我读到的另一件事是,这样的加载可能违反了严格的别名规则,但代码编译时没有使用-Wstrict-aliasing -Werror(我很久以前启用)发出任何警告。
我应该填充uint8_t 数组中的数据以确保访问对齐,还是可以安全地忽略警告?
【问题讨论】:
-
如果您希望避免未定义的行为,则只能通过 std::memcpy 访问数组中的数据(进入/来自目标数据类型)。 ponters(
uint8_t*和char*除外)的直接访问是 UB。 -
“我的理解是 CPU 会正确处理此类访问,但可能需要做额外的工作来获取数据。” 哪个 CPU? x86 对非对齐访问很好,但在其他 CPU 上,它们是致命错误。在其他 CPU 上,用户可以选择错位是否是致命错误,或者是否会以巨大的性能成本进行修复。
-
@CodyGray 谢谢,我澄清了这个问题。
-
@RichardCritten 谢谢,如果您将您的评论作为答案,我会接受。使用 std::memcpy() 修复了消毒剂引发的警告。
标签: c++ memory undefined-behavior memory-alignment