下面是我需要找出输出的语句:
int k = 35;
printf("%d %d %d", k == 35, k = 50, k > 40);
上述语句的输出(在gcc编译器中):
0 50 0
我用gcc编译器在VSCode中运行了上面的代码。
我期望的输出是:
但是,实际输出为:
0 50 0
有趣的是,如果我将printf()语句拆分如下:
int k = 35;
printf("%d ", k == 35);
printf("%d ", k = 50);
printf("%d ", k > 40);
实际输出与预期一致,即:
这就是为什么我对原始问题中printf()语句的行为感到困惑,为什么输出是“0500”而不是“1501”?
1条答案
按热度按时间fdbelqdn1#
C标准没有对这个程序的行为指定任何要求,它可能打印“1 50 1”或“0 50 0”,它可能打印其他输出,它可能中止,或者它可能做其他事情。
参数
k = 50
的副作用是更改k
的值。(在赋值表达式中,副作用是更改左操作数的值。主要作用是使表达式具有左操作数的新值。)参数k == 35
和k > 40
使用k
的值计算值。C标准中规定函数调用行为的条款6.5.2.2并没有规定函数调用的参数之间的任何顺序,然后另一个条款C 2018 6. 5 2说:
如果标量对象上的副作用相对于同一标量对象上的不同副作用或使用同一标量对象的值进行的值计算而言是无序的,则该行为是未定义的...
因此,这个
printf
调用对k
有副作用,k
是一个标量对象,相对于使用k
的值进行的值计算是无序的,所以C标准没有定义程序的行为。C标准没有定义这种行为的一个根本原因是我们希望编译器优化程序的性能,这可能涉及到对表达式进行部分求值并以任何顺序执行这些部分。例如,如果一个函数的几个参数有一个公共子表达式,我们通常希望编译器计算公共子表达式,并在多个参数中多次使用它的值,而不是每次都重新计算。所以我们希望允许编译器混合执行多个表达式,如果这样可以提高程序性能的话。C程序的作者有责任理解这些规则,避免混合表达式,以免以不希望的方式相互干扰。
另一方面,有些表达式看起来像单个运算,如
k = 50
,但实际上可能不是。编译器可能通过使用多个指令执行64位运算,在只有32位运算的计算机硬件上支持64位整数算术。例如,它可能通过将两个数的低32位相加来执行64位加法。将低32位存储到结果中,将数字的高32位与低32位的进位相加,然后将高32位存储到结果中。当您将此事实与表达式计算的混合相结合时,有可能像k > 40
这样的表达式的某些部分(可能比较高位)在k = 50
的某些部分之前求值(可能存储低位),而其他部分在它们之后求值。这意味着,当你有像k == a
,k = b
这样的参数时,k > c
,则以不同顺序计算各部分可能产生的结果实际上是不可能的,如果每个参数以三个独立事物的六种可能顺序中的任何一种单独计算。