本文共 2400 字,大约阅读时间需要 8 分钟。
本节书摘来自异步社区《C语言解惑》一书中的第1章,第1.6节,作者 傅道坤,更多章节内容可以访问云栖社区“异步社区”公众号查看
请问,下面这个程序的输出是什么?
define PRINT3(x,y,z) \ printf(#x "=%d\t" #y "=%d\t" #z "=%d\n",x,y,z)main(){ int x, y, z; x = y = z = 1; ++x || ++y && ++z; PRINT3(x,y,z); (1.6.1) x = y = z = 1; ++x && ++y || ++z; PRINT3(x,y,z); (1.6.2) x = y = z = 1; ++x && ++y && ++z; PRINT3(x,y,z); (1.6.3) x = y = z = -1; ++x && ++y || ++z; PRINT3(x, y,z); (1.6.4) x = y = z = -1; ++x || ++y && ++z; PRINT3(x,y,z); (1.6.5) x = y = z = -1; ++x && ++y && ++z; PRINT3(x,y,z); (1.6.6)}
输出:
x=2 y=1 z=1 (1.6.1)x=2 y=2 z=1 (1.6.2)x=2 y=2 z=2 (1.6.3)x=0 y=-1 z=0 (1.6.4)x=0 y=0 z=-1 (1.6.5)x=0 y=-1 z=-1 (1.6.6)
解惑1.6 操作符的优先级和求值顺序
初始值:x = 1, y = 1, z = 1
++ x || ++ y && ++ z
((++ x) || ((++ y) && (++z))) 把操作数绑定到操作符上。
(2 || ((++ y) && (++z))), 此时x=2 按从左到右的顺序依次求值。
(TRUE ||任意值) 因为“||”操作符的左操作数是TRUE,所以没有必要继续求值了。事实上,C语言肯定不会继续求值——按照C语言里的有关规则,在按从左到右的顺序对一个逻辑表达式求值的时候,只要知道了它的实际结果,就不会再对其余部分求值。具体到这道谜题,这意味着y和z的值仍将是1。
TRUE, 即1
初始值:x = 1, y = 1, z = 1
++ x && ++ y || ++z
(((++ x) && (++ y))||(++z))
((TRUE && (++ y))||(++z)), 此时x=2
((TRUE && TRUE)||(++z)), 此时y = 2 按从左到右的顺序依次求值。
(TRUE ||(++z))
TRUE, 即1 变量z的值没有发生变化。
初始值:x = 1, y = 1, z = 1
++ x && ++ y && ++ z
(((++ x) && (++ y)) && (++z))
((2 && 2) && (++z)), 此时x = 2,y = 2
(TRUE && (++z))
(TRUE && TRUE), 此时z =2
TRUE, 即1
初始值:x = -1, y = -1, z = -1
++ x && ++ y || ++ z
(((++ x) && (++ y)) || (++z))
((0 && (++ y)) || (++z)), 此时x=0
((FALSE && (++y)) || (++z))
(FALSE || (++z)) 因为“&&”操作符的左操作数是FALSE,所以没有必要对++y求值。可是,“||”操作的结果现在还不能确定。
(FALSE || (0)), 此时z = 0`
(FALSE || FALSE)
FALSE, 即0
初始值:x = -1, y = -1, z = -1
++ x||++ y && ++z
((++ x)||((++ y) && (++z)))
(FALSE||((++ y) && (++z))), 此时x=0
(FALSE||(FALSE && (++z))), 此时y = 0
(FALSE||(FALSE)
FALSE, 即0
初始值:x = -1, y = -1, z = -1
++ x && ++ y && ++z
(((++ x) && (++ y))&&(++z))
((FALSE && (++ y))&&(++z)), 此时x=0
(FALSE && (++z))
FALSE, 即0
关于逻辑操作符的副作用:正如你们现在已经体会到的那样,C语言里的逻辑表达式的求值有一定的难度,因为是否需要对逻辑操作符的右操作数求值取决于其左操作数的求值结果。这种根据具体情况来决定是否对右操作数求值的做法是逻辑操作的一个有用的属性。可是,如果在逻辑表达式的右半部分隐藏着副作用,那么就难免会留下隐患——那些副作用可能会发作,也可能不会发作。一般说来,谨慎对待副作用总是没错的,这在逻辑表达式中就更为重要了。
[1] lvalue,能够出现在赋值操作符“=”左侧的记号。——译者注
[2] 这里所说的“副作用”是指在执行一条本身并无语法错误的语句时会产生的难以确定的后果。C程序的副作用几乎都与变量的值(比如上面这个例子里的递增操作或一个赋值操作的计算结果)无法预料有关。
转载地址:http://uapvl.baihongyu.com/