任何人都可以帮我理解下面代码的输出:
int main()
{
int a=35;
printf("%d %d %d %d %d",a--,a,a=20,a++,a=39);
return 0;
}
输出:20 19 19 39 19
了解如何在 c 中的 printf 函数中处理(编译)赋值。
这是未指定的行为。 C 标准中没有指定函数参数的求值顺序,因此它可以按任何顺序发生。
人们已经在评论中给了你一些链接,你可以阅读。但总而言之,有一种东西叫做“序列点”。这些确保之前需要执行的所有内容都已执行,然后程序可以继续。在两个序列点之间,指令可以按任意顺序执行。
来自C11标准:
3.4.4:
未指定行为
使用未指定的值或本国际标准规定的其他行为 两种或多种可能性,并且对任何选择中的选择不施加进一步的要求 实例示例 未指定行为的一个示例是计算函数参数的顺序。
6.5.2.2.10 说
在功能指示符和实际值的评估之后有一个序列点 参数,但在实际调用之前。 调用函数中的每个计算(包括 其他函数调用),在之前或之后没有特别排序 被调用函数体的执行顺序不确定 被调用函数的执行。
换句话说,函数参数的求值之间没有顺序点,因此它们可以按照编译器认为的任何顺序进行求值。
为了完成答案,这也是未定义的行为,因为您尝试在两个序列点之间多次更改
a
的值。
6.5.2:
如果标量对象上的副作用相对于同一标量对象上的不同副作用或使用相同标量的值的值计算是无序的 对象,行为未定义。如果表达式的子表达式有多个允许的排序,并且在任何排序中出现此类未排序的副作用,则行为是未定义的。84)
84) 他的段落呈现未定义的语句表达式,例如
i = ++i + 1;
a[i++] = i;
同时允许
i = i + 1;
a[i] = i;
printf("%d %d %d %d %d",a--,a,a=20,a++,a=39);
这是未定义的行为。
这意味着该程序可以打印:
20 19 19 39 19
或0 0 0 0 0
,甚至格式化您的硬盘。
(C99, 6.5p2) “在上一个和下一个序列点之间,对象的存储值最多应通过表达式的求值修改一次。
当然,违反不是约束的“应”意味着程序调用未定义的行为(参见 C99 中的 4.p2)。