用C语言进行实验 #包括 int main(){ int x=99; printf(“%d%d\n”,1>scanf(“%d”、&x)?scanf(“%d”、&x):scanf(“%d”、&x),x); }

用C语言进行实验 #包括 int main(){ int x=99; printf(“%d%d\n”,1>scanf(“%d”、&x)?scanf(“%d”、&x):scanf(“%d”、&x),x); },c,C,那么扫描的值会发生什么变化呢。 假设第一个输入是11。所以最左边的scanf返回1。因此,根据规则,将执行最右边的scanf。但printf最右边的%d未打印扫描的值。它显示99。您有未定义的行为 这是因为您正在修改一个值并在没有插入序列点的情况下访问该值。具有相同问题的简化示例: #include<stdio.h> int main() { int x = 99; printf("%d %d\n",1 > scanf("%d",&x) ? scanf

那么扫描的值会发生什么变化呢。 假设第一个输入是11。所以最左边的scanf返回1。因此,根据规则,将执行最右边的scanf。但printf最右边的%d未打印扫描的值。它显示99。

您有未定义的行为

这是因为您正在修改一个值并在没有插入序列点的情况下访问该值。具有相同问题的简化示例:

#include<stdio.h>

int main() {
    int x = 99;
    printf("%d %d\n",1 > scanf("%d",&x) ? scanf("%d",&x): scanf("%d",&x),x);
}
或者这个:

int x = 0;
printf("%d %d", x++, x); /* <--- UB! */

现在,用感叹号标记的行是非常荒谬的,但至少它是UB自由的。

函数参数可以按任何顺序求值。在本例中,在调用scanf之前,x的计算结果似乎是99。C中未指定函数参数求值的顺序。这是:

逗号运算符不保证从左向右求值,但在函数调用中分隔参数的逗号不是逗号运算符。[…]未指定函数调用参数的求值顺序


因为在修改x的scanf和计算x的函数参数之间没有序列点,所以您正在调用未定义的行为,正如rodrigo在回答中所解释的那样。

这不可能出现在生产代码中。充其量,它探索了官方规范的边缘(这可能是一件好事)。在最坏的情况下,你随机连接函数和运算符,然后问我们“为什么我会这样?”你真的想在
printf
调用的参数列表中使用
?:
运算符调用
scanf
,两次吗?也许这只是一个智力练习,但这是一个非常糟糕的主意,即使它真的起作用了,在这种情况下,它不起作用。是的,因为这是一个电脑爱好者了解电脑的地方。你们是拥有信息和智慧的人。每个人都应该问你。实验也带来了一些发现。在那之前我不知道“序列点”的事。但现在我要检查一下,发现是在未勘探的地区进行的。但这一领域已经得到了很好的探索。而且,它不是一些自然现象,它是由人根据规格制造的。因此,这些规范可以回答您可能遇到的任何问题。实验不是找出这些规范的好方法,因为一旦你有了UB,你可能会在同一个实验中得到不同的结果。好吧。从我的角度来看,这是一个发现,我明白了你的观点。好吧,我会检查一下。我很高兴有人在分享信息。实际上,+1。“因为我的声望不够高,不能给你投票。”帕纳巴桑亚尔:不。一般来说,对论点的评价顺序是不明确的。但这里的问题是没有序列点的修改和使用,即UB,这是任何情况都可能发生的。@ParnabSanyal:不。编译器可以根据需要以任何顺序计算
printf
的参数。只有少数几个地方C保证表达式中特定的求值(执行)顺序;否则,求值顺序是未指定的。@ParnabSanyal:如果您在
printf
语句中看到任何类型的模式,这只是巧合。谢谢您的参考链接
int x = 1;
printf("%d %d", x = 11, x); /* <--- UB! */
int x = 0;
printf("%d %d", x++, x); /* <--- UB! */
int x[10] = {0}, i = 0;
printf("%d %d", x[i++], x[i++]); /* <--- UB! */
int x = 99;
int y = 1 > scanf("%d",&x) ? scanf("%d",&x): scanf("%d",&x); /* ARGH! */
printf("%d %d\n", y, x);