【问题标题】:Additional questions on memory alignment关于内存对齐的附加问题
【发布时间】:2019-07-03 18:52:42
【问题描述】:

以前有一些关于内存对齐的很好的答案,但我觉得没有完全回答一些问题。

例如:

What is data alignment? Why and when should I be worried when typecasting pointers in C?

What is aligned memory allocation?

我有一个示例程序:

#include <iostream>
#include <vector>
#include <cstring>

int32_t cast_1(int offset) {
  std::vector<char> x = {1,2,3,4,5};
  return reinterpret_cast<int32_t*>(x.data()+offset)[0];
}

int32_t cast_2(int offset) {
  std::vector<char> x = {1,2,3,4,5};
  int32_t y;
  std::memcpy(reinterpret_cast<char*>(&y), x.data() + offset, 4);
  return y;
}

int main() {
  std::cout << cast_1(1) << std::endl;
  std::cout << cast_2(1) << std::endl;
  return 0;
}

cast_1 函数输出 ubsan 对齐错误(如预期),但 cast_2 没有。但是,cast_2 对我来说可读性要差得多(需要 3 行)。 cast_1 的意图看起来非常清楚,即使它是 UB。

问题:

1) 为什么是cast_1 UB,意图非常明确?我了解对齐可能存在性能问题。

2) cast_2 是修复 cast_1 的 UB 的正确方法吗?

【问题讨论】:

    标签: c++ memory-alignment


    【解决方案1】:

    WRT 第一个问题,编译器为您处理这个问题是微不足道的,真的。它所要做的就是对程序中的所有其他非字符加载进行悲观

    对齐规则是精确编写的,因此编译器可以生成在许多平台上执行良好的代码,其中对齐的内存访问是一种快速的本机操作,而未对齐的访问相当于您的 memcpy。除了可以证明对齐的地方,编译器必须以缓慢而安全的方式处理每个加载。

    【讨论】:

      【解决方案2】:

      1) 为什么是cast_1UB?

      因为语言规则是这样说的。实际上有多个规则。

      1. 访问对象的偏移量不满足int32_t 的对齐要求(对齐要求为 1 的系统除外)。不符合类型的对齐要求就不能创建对象。

      2. char 指针不能被 int32_t 指针别名。

      2) cast_2 是修复 cast_1 的 UB 的正确方法吗?

      cast_2 具有明确定义的行为。该函数中的reinterpret_cast 是多余的,使用魔法常量是不好的(使用sizeof)。

      【讨论】:

      • 对于cast_2std::memcpy(&amp;y, x.data() + offset, sizeof(y)); 更好吗?对于第一个问题,真的没有比“规则这么说”更好的答案了吗?
      • 嗯,任何东西都是 UB 的原因只是标准这么说。这就是定义。我在回答中描述了动机。是的,该代码看起来不错。
      • @thc 我不清楚您所说的“更好的答案”是什么意思。是的,使用 sizeof 会更好,并且可以保证在大小不是 4 的系统上的正确性。作为第二个操作数的替代方案,您可以使用 &amp;x[offset],但这取决于您自己的喜好。
      • 感谢您的两位 cmets!
      猜你喜欢
      • 2011-05-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-03-09
      • 1970-01-01
      • 1970-01-01
      • 2011-10-08
      • 2016-03-14
      相关资源
      最近更新 更多