【问题标题】:Pointer Alignment of Function Arguments in C++17C++17 中函数参数的指针对齐
【发布时间】:2018-06-01 17:01:11
【问题描述】:

我看到 C++17 引入了带有 std::align_val_t 的对齐新表达式,用于需要比 new 自然提供的更大对齐的对象。这很棒,但让我思考:

为什么指针对齐不是指针类型的一部分?

例如:

long foo(long *x) {
  return *x; // here, the compiler do an aligned load
             // correct as (long*) is expected to be aligned
}

假设指针在 64 位上对齐(在我的机器上)。 但如果我执行以下操作,编译器不会警告我:

long bar(char *x) {
  return foo((long*) x); // here, the compiler do an aligned load, risky!
}

long pop(char *z) {
  return bar(z + 1); // here, the compiler do an aligned load too!
}

我通过从打包结构中传递一个指向字段的指针来得到警告:

struct ugly {
  char x;
  long y;
} __attribute__((packed));

long kun(ugly *a) {
  return a->y; // here, the compiler do an unaligned load, correct!
}

long zip(ugly *a) {
  return foo(&a->y); // here, the compiler do an aligned load, incorrect!
                     // but warns me about it.
}

但为什么不是错误,类似于const_cast

标准对对齐有何规定?

是否所有编译器都在做不正确的假设,或者是未定义/实现定义的行为来提供指向函数的未对齐指针?

您可以在此处查看它们的实际效果:https://godbolt.org/g/9ddbiq

编辑:修复了sn-p代码,并提供了godblot链接。

【问题讨论】:

  • 它可能是特定于实现的(和 UB)。对齐在ABI 级别很重要,不仅在语言级别
  • 您的示例不是合法的 c++。它不会编译,因为不能将void* 分配给long*,也不能将3 分配给long*。此外,您似乎正在尝试取消引用设置为地址 3 的指针。
  • 对于这个问题,我们真的需要minimal reproducible example,可能带有指向godbolt.org上示例的链接

标签: c++ compiler-errors


【解决方案1】:

标准对对齐有何规定?

这很简单:存在的每个 T 类型的对象都有正确的对齐方式。

如果您使用放置 new 并提供对齐不足的指针,则 UB 结果。如果您替换 new 分配器并为正在分配的类型提供对齐不足的指针,则会导致 UB。如果您的 std::allocator<T>::allocate 返回的指针未与 T 正确对齐,则 UB 结果。以此类推。

未定义的行为不需要编译失败。

【讨论】:

  • 即使块实际上足够大以容纳对象,它仍然是UB。一些平台可以处理未对齐的数据(只是性能受到严重影响,例如 x86),许多其他平台甚至无法做到这一点,并且会在尝试时出错。
  • 我明白了。所以“打包”结构是创建这种不正确对象的唯一方法(使用new),这证明了为什么它不是标准的一部分。
猜你喜欢
  • 1970-01-01
  • 2020-01-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-04-18
  • 2016-09-07
  • 1970-01-01
  • 2013-09-12
相关资源
最近更新 更多