根据标准,T 数组到 T 指针的数组是否在 C/C++ 中强制转换为合法操作?

Den*_*rov 1 c++ arrays pointers

我已经阅读了标准的所有相关条款,但对于这种特殊情况,我无法正确解释它们

const int arr[4][2] = {};
const int *ptr1 = (const int*)arr; // Is it OK/NOK and why?
const int *ptr2 = arr[0];          // Is this the same?
const int *ptr3 = &arr[0][0];      // Same?
Run Code Online (Sandbox Code Playgroud)

标准对这个演员有什么看法?

更新。

这是另一个相关的问题:

int i0 = ptr1[0];
int i2 = ptr2[2];
int i7 = ptr3[7];
Run Code Online (Sandbox Code Playgroud)

标准对直接从这些指针获取值有何看法?

eer*_*ika 5

根据标准,T 数组到 T 指针的数组是否在 C/C++ 中强制转换为合法操作?

const int *ptr1 = (const int*)arr; // Is it OK/NOK and why?
Run Code Online (Sandbox Code Playgroud)

是的,这是合法的。arr将首先衰减到指向第一个元素的指针,即const int(*)[4]对象指针。const int *ptr也是对象指针类型。在 C++ 中,所有对象指针类型都可以显式转换为不同类型的对象指针。

然而,虽然强制转换是合法的,但由于“严格别名”规则,通过指针间接访问并尝试访问指向的对象是不合法的。洗后应该没问题:

auto ptr = std::launder(reinterpret_cast<const int*>(arr));
Run Code Online (Sandbox Code Playgroud)

但最好只使用:

auto ptr = &arr[0][0]
Run Code Online (Sandbox Code Playgroud)

这达到了相同的目的。但是,它无助于访问第一个子数组之外的元素。


UPD

const int *ptr2 = arr[0];          // Is this the same?
const int *ptr3 = &arr[0][0];      // Same?
Run Code Online (Sandbox Code Playgroud)

这些都不是演员表,两者都是格式良好的并且实际上是等效的。

这是另一个相关的问题:

int i0 = ptr[0];
int i2 = ptr[2];
int i7 = ptr[7];
Run Code Online (Sandbox Code Playgroud)

即使洗钱,这也是未定义的行为。您只能arr[0]通过重新解释的指针进行访问,因为它是从指向第一个子数组的衰减指针派生的。访问ptr[0]ptr[1]会被罚款你ptr2ptr3我洗过的例子。

  • `std::launder` 不修复严格别名 UB。请参阅此处的第 2 条和第 4 条:https://en.cppreference.com/w/cpp/utility/launder (2认同)