就是下面的代码:
#include <stdio.h>
void case1(int array[][printf("hello ")][printf("world ")]) {}
int i = 0;
void case2(int array[][i++][i++]) {}
int main(void) {
case1(0);
case2(0);
printf("%d \n", i);
}
应该是:
world hello 2
就像在 gcc14.2.1 上一样?hello world 2
就像 clang18.1.8 上那样?VLA维度大小的评估是无序的、不确定序的、有某种顺序的吗?有顺序点吗
我尝试阅读https://port70.net/~nsz/c/c11/n1570.html、https://port70.net/~nsz/c/c23/n3220.pdf、https:/ /en.cppreference.com/w/c/language/eval_order 和https://en.cppreference.com/w/c/language/array但没有发现任何相关内容。
这是 C 标准 (C23) 中的相关段落:
6.8 语句和块
[...]
语义
[...]
- 完整表达式是不属于另一个表达式的一部分的表达式,也不属于声明符或抽象声明符的一部分。还有一个隐式完整表达式,其中评估可变修改类型的非常量大小表达式;在该完整表达式中,不同大小表达式的求值彼此之间是无序的。在完整表达式的求值和下一个要求值的完整表达式的求值之间存在一个序列点。
这似乎暗示着对您的问题的以下答复:
VLA维度大小的评估是无序的、不确定序的、有某种顺序的吗?
正如上一段中明确指出的,VLA 尺寸大小的评估彼此之间没有顺序。
有顺序点吗?
是的:VLA 维度是隐式完整表达式并且在完整表达式的求值和下一个要求值的完整表达式的求值之间存在一个序列点。
代码应该是:
- 打印
就像在 gcc14.2.1 上一样?world hello 2
此行为无法保证,但似乎符合要求。
- 打印
就像在 clang18.1.8 上一样?hello world 2
这种行为并不能得到保证,但似乎也符合要求。 似乎不允许其他行为。
- 是实现定义的行为?为了
?为了case1
?case2
- 是未定义的行为?为了
?为了case1
?case2
对于
case1
,因为两个printf
语句的评估是无序的:一致性实现有可能表现出不同的行为(如观察到的),但给定的一致性实现也有可能在不同的运行中表现出不同的行为!
输出是不可预测的,因此行为不是实现定义的,但它似乎不符合 C 标准中“未定义行为”的定义。 请注意,函数
array
的
case1
参数的第二个和第三个数组维度在所有情况下都将定义为 6
。
case2
,行为未定义:
array
参数的至少一个维度计算为 0
,这会调用未定义的行为。另一方面,如果未定义的行为被删除,i
会通过表达式之间的序列点递增两次,从而将最终值确定地带到
2
。如果在函数定义中将 i++
更改为
++i
,未定义的行为就会消失,并且 printf
语句必须输出 2
。请注意,为 case2
的数组参数定义的维度在每次运行中可能有所不同,但由于该函数不使用这些维度,因此无法观察到任何内容。