此问题在此处已有答案:
One-dimensional access to a multidimensional array: is it well-defined behaviour?(4个答案)
May I treat a 2D array as a contiguous 1D array?(6个答案)
10天前关闭。
请检查下面的代码:
#include "stdio.h"
#define N 2
#define M 2
int main(void)
{
int two_d[N][M];
for(size_t i = 0; i < N*M; ++i) {
two_d[0][i] = i; // <---- Pay attention to this line!
}
for(size_t i = 0; i < N; ++i) {
for(size_t j = 0; j < M; ++j) {
printf("%d\n", two_d[i][j]);
}
}
return 0;
}
字符串
请不要对这个例子持怀疑态度,并迅速判断它是人为的--这个例子是你在一个非常真实的和非常知名的项目中发现的(这个项目非常有名)。
我希望有一个好的语言律师的电话号码!
1.一方面,内存保证是按顺序布局的,所以我一般不会访问对象之外的任何东西;
1.另一方面,我显然是在访问第一个1d数组之外的内存--这样做是UB。
示例在我的机器上编译并运行良好。Godbolt先生展示了C和C++编译器都做同样的事情,并且通过优化都处理like a doctor。
所以,问题是:
1.这在C中法律的吗?
1.这在C++中法律的吗?
标准报价将不胜感激。
2条答案
按热度按时间46scxncf1#
在C++中,下标表达式的含义在expr.sub中给出:
使用内置的下标运算符,应该存在一个 expression-list,由单个 assignment-expression 组成。其中一个表达式应该是类型为“array of
T
”的左值或类型为“pointer toT
”的右值,另一个表达式应该是无作用域枚举或整型的右值。结果的类型为“T
”。类型“T
”应为完全定义的对象类型。表达式E1[E2]
与*((E1)+(E2))
相同(根据定义),除了在数组操作数的情况下,如果该操作数是左值,则结果是左值,否则是x值。关于
+
在expr.add中的规则:当一个整型的表达式
J
与一个指针型的表达式P
相加或相减时,结果的类型为P
。P
的计算结果为空指针值,而J
的计算结果为0,则结果为空指针值。(4.2)P
指向具有 n 个元素的数组对象x
的数组元素 i([dcl.array]),则表达式P + J
和J + P
(其中J
具有值 j)如果0 <= i + j <= n 则指向x
的(可能-假设的)数组元素 i + j,并且表达式P - J
如果0 <= i - j <= n 则指向x
的(可能-假设的)数组元素 i - j。*否则行为未定义
您的代码段调用了未定义的行为。
在C中,规则非常相似。从6.5.2.1/2开始,数组下标:
后缀表达式后跟方括号中的表达式
[]
是数组对象元素的下标指定。下标运算符[]
的定义是E1[E2]
与(*((E1)+(E2)))
相同。由于适用于二进制+
运算符的转换规则,如果E1
是数组对象(相当于指向数组对象初始元素的指针),E2
是整数,则E1[E2]
指定E1
的第E2
个元素(从零开始计数)。然后,根据6.5.6/8,加法运算符:
当一个整数类型的表达式与指针相加或相减时,结果具有指针操作数的类型。如果指针操作数指向数组对象的元素,并且数组足够大,则结果指向与原始元素偏移的元素,使得结果和原始数组元素的下标之差等于整数表达式。换句话说,如果表达式
P
指向数组对象的第 i 个元素,则表达式(P)+N
(相当于N+(P)
)和(P)-N
(其中N
的值为 n)分别指向数组对象的第 i+n 个元素和第 i−n 个元素,前提是它们存在。此外,如果表达式P
指向数组对象的最后一个元素,则表达式(P)+1
指向数组对象的最后一个元素之后的一个元素,如果表达式Q
指向数组对象的最后一个元素之后的一个元素,则表达式(Q)-1
指向数组对象的最后一个元素。如果指针操作数和结果都指向同一个数组对象的元素,或者指向数组对象最后一个元素之后的元素,则计算不应产生溢出;否则,行为未定义。如果结果指向数组对象的最后一个元素之后的一个元素,则不应将其用作计算的一元*
运算符的操作数。就像在C++中一样,超出数组边界是未定义的行为,对于“但是如果旁边有另一个数组怎么办”没有特殊的豁免。
mlnl4t2r2#
这在C中法律的吗?
这在C++中法律的吗?
不,两个都是UB
int array[x][y]
是x
阵列的阵列,具有y
int
元素。如果第二个下标是>= y
,那么您访问y
元素int
数组的边界之外。在
'C'
中,您可以通过使用union
来防止UB。字符串