Ser*_*sta 5 c arrays strict-aliasing multidimensional-array language-lawyer
众所周知,二维数组是数组的数组,并且标准要求它是连续分配的非空对象集(6.2.5 类型 §20)——这里的对象是一维数组。
众所周知,对于所有常见的实现,以下等式对于T arr2d[X][Y]其中 T 是一个类型和 X 和 Y 整数常量的情况是正确的:
(char *) &arr2d[i][j] == (char *) &arr2d[0][0] + i * Y * sizeof(T) + j * sizeof(T)
Run Code Online (Sandbox Code Playgroud)
上面让我们认为可以允许为 2D 数组和相同大小的 1D 数组甚至另一个具有相同总大小的 2D 数组取别名:
例如,以下程序编译并运行时没有警告,并提供预期的输出:
#include <stdio.h>
int main() {
int i, j, k=0;
int arr2d[3][4]; // array of 3 array of 4 ints
int *arr1 = &arr2d[0][0]; // pointer to first element of an array of 12 ints (1)
int (*arrx)[3] = (int(*)[3]) arr1; //pointer to first row of an array of arrays of 3 ints
//(2)
for (i=0; i<12; i++) arr1[i] = k++; // (3)
for (i=0; i<3; i++) {
for (j=0; j<4; j++) {
printf("%3d", arr2d[i][j]);
}
putc('\n', stdout);
}
for (i=0; i<4; i++) {
for (j=0; j<3; j++) {
printf("%3d", arrx[i][j]);
}
putc('\n', stdout);
}
return 0;
}
Run Code Online (Sandbox Code Playgroud)
但:
我的问题是:
Ser*_*sta -1
即使严格的别名规则允许从包含一种类型的对象访问该对象,标准中也有两个元素表明不允许将 2D 数组别名为相同大小的 1D 数组:
\n\n兼容型
\n\n\n\n\n6.2.7 兼容型和复合型
\n\n1 如果两个类型的类型相同,则它们具有兼容类型。
\n\n
...
\n 3 复合类型可以由两种兼容的类型构造而成;它是与这两种类型兼容并满足以下条件的类型:\n
\n\n- 如果一种类型是已知常量大小的数组,则复合类型是该大小的数组;否则,如果一种类型是可变长度数组,则复合类型就是该类型。
\n
...这些规则递归地应用于派生这两种类型的类型。
\n
一致性:
\n\n\n\n\n4 一致性
\n\n...
\n\n\n
\n- ...在本国际\n标准中,未定义的行为通过文字\xe2\x80\x98\xe2\x80\x98未定义的行为\xe2\x80\x99\xe2\x80\x99或通过省略任何显式定义来表示\n 的行为。这三者的侧重点没有区别;它们都描述\n \xe2\x80\x98\xe2\x80\x98未定义的行为\xe2\x80\x99\xe2\x80\x99。
\n- 在所有其他方面都正确、对正确数据进行操作、包含未指定行为的程序应是正确的程序,并且按照 5.1.2.3 进行操作。
\n
\n ...- 严格遵守的程序应仅使用本国际标准中指定的语言和库的功能。2)它不应产生依赖于任何未指定、未定义或实现定义的行为的输出,并且不应超过任何\n n 最低实施限制。
\n
我的理解是,标准未指定二维数组与一维数组的别名,因此会导致未定义的行为。使用它的程序仍然是应成功编译的正确程序,但其输出未指定
\n\n严格遵守的程序不应将 2D 数组别名为 1D 数组。
\n\n话虽这么说,通用实现允许它并按预期处理它(每个未定义的行为都允许......),以便不破坏严重依赖它的遗留代码。
\n