c++ - 严格别名和对编译时 C 数组的引用

标签 c++ language-lawyer undefined-behavior strict-aliasing

鉴于以下代码

#include <cassert>
#include <climits>
#include <cstdint>
#include <iostream>

static_assert(CHAR_BIT == 8, "A byte does not consist of 8 bits");

void func1(const int32_t& i)
{
    const unsigned char* j = reinterpret_cast<const unsigned char*>(&i);
    for(int k = 0; k < 4; ++k)
        std::cout << static_cast<int>(j[k]) << ' ';
    std::cout << '\n';
}

void func2(const int32_t& i)
{
    const unsigned char (&j)[4] = reinterpret_cast<const unsigned char (&)[4]>(i);
    for(int k = 0; k < 4; ++k)
        std::cout << static_cast<int>(j[k]) << ' ';
    std::cout << '\n';
}

int main() {
    func1(-1);
    func2(-1);
}


从语言规则可以清楚地看出func1很好,作为指向 unsigned char 的指针可以别名任何其他类型。我的问题是:这是否扩展到对已知长度的 C 数组的 C++ 引用?直觉上我会说是的。是 func2定义明确还是会触发未定义的行为?

我已经尝试使用 Clang 和 GCC 以及 -Wextra -Wall -Wpedantic 的所有可能组合来编译上述代码。和 UBSAN,并且没有收到任何警告并且总是相同的输出。这显然并没有说明没有 UB,但我无法触发任何通常的严格别名类型优化错误。

最佳答案

这是未定义的行为。

关于reinterpret_cast的含义我们有 [expr.reinterpret.cast]

11 A glvalue expression of type T1 can be cast to the type “reference to T2” if an expression of type “pointer to T1” can be explicitly converted to the type “pointer to T2” using a reinterpret_­cast. The result refers to the same object as the source glvalue, but with the specified type. [ Note: That is, for lvalues, a reference cast reinterpret_­cast(x) has the same effect as the conversion *reinterpret_­cast(&x) with the built-in & and * operators (and similarly for reinterpret_­cast(x)).  — end note ] No temporary is created, no copy is made, and constructors or conversion functions are not called.



这告诉我们 cast int func2只要 reinterpret_cast<const unsigned char (*)[4]>(&i) 就有效已验证。这里没有震惊。但问题的关键在于,您可能无法从指针转换中获得任何有意义的信息。关于这个主题,我们在 结束了这个话题。 [基础.compound] :

4 Two objects a and b are pointer-interconvertible if:

  • they are the same object, or
  • one is a standard-layout union object and the other is a non-static data member of that object ([class.union]), or
  • one is a standard-layout class object and the other is the first non-static data member of that object, or, if the object has no non-static data members, the first base class subobject of that object ([class.mem]), or
  • there exists an object c such that a and c are pointer-interconvertible, and c and b are pointer-interconvertible.

If two objects are pointer-interconvertible, then they have the same address, and it is possible to obtain a pointer to one from a pointer to the other via a reinterpret_­cast. [ Note: An array object and its first element are not pointer-interconvertible, even though they have the same address.  — end note ]



这是有意义的指针转换的详尽列表。所以我们不允许获得这样的数组地址,因此它不是有效的数组泛左值。因此,您对转换结果的进一步使用是不确定的。

关于c++ - 严格别名和对编译时 C 数组的引用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58413515/

相关文章:

c++ - 跨平台可重复数字生成器

c++ - 具有单个互斥体的 std::scoped_lock 行为

C++ 字符串函数 - 为什么它们通常具有未指定的复杂性?

c++ - Eclipse ide 需要与 MISRA 规则集成

c++ - 游戏逻辑的异步屏幕更新,C++

c++ - 共享首选项实现

c++ - 仅通过指针转换创建可互换的类类型,而无需分配任何新对象?

c++ - 为什么我的代码无法处理大数组输入(>10000)?

c++ - 如何在不获取未定义行为的情况下重新解释或转换具有已知内存布局的对象

java - 可用的私有(private)变量