zl程序教程

您现在的位置是:首页 >  后端

当前栏目

《C语言解惑》一1.6 操作符的优先级和求值顺序

C语言 顺序 优先级 操作符 1.6 解惑 求值
2023-09-11 14:17:33 时间

本节书摘来自异步社区《C语言解惑》一书中的第1章,第1.6节,作者 傅道坤,更多章节内容可以访问云栖社区“异步社区”公众号查看

谜题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)


bf797fb4bb1cdc72472a717437ca980ad03ae269

输出:

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)


d51baaea67b526c7af1a6aaf503e28300497fec6

解惑1.6 操作符的优先级和求值顺序

1.6.1

初始值: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

1.6.2

初始值: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的值没有发生变化。

1.6.3

初始值: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

1.6.4

初始值: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

1.6.5

初始值: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

1.6.6

初始值:x = -1, y = -1, z = -1

++ x ++ y ++z

(((++ x) (++ y)) (++z))

((FALSE (++ y)) (++z)), 此时x=0

(FALSE (++z))

FALSE, 即0

关于逻辑操作符的副作用:正如你们现在已经体会到的那样,C语言里的逻辑表达式的求值有一定的难度,因为是否需要对逻辑操作符的右操作数求值取决于其左操作数的求值结果。这种根据具体情况来决定是否对右操作数求值的做法是逻辑操作的一个有用的属性。可是,如果在逻辑表达式的右半部分隐藏着副作用,那么就难免会留下隐患——那些副作用可能会发作,也可能不会发作。一般说来,谨慎对待副作用总是没错的,这在逻辑表达式中就更为重要了。


a0469e1b135de4eab83a8b1a92d9c8800eb4bbb0

[1] lvalue,能够出现在赋值操作符“=”左侧的记号。——译者注

[2] 这里所说的“副作用”是指在执行一条本身并无语法错误的语句时会产生的难以确定的后果。C程序的副作用几乎都与变量的值(比如上面这个例子里的递增操作或一个赋值操作的计算结果)无法预料有关。


【C语言初阶(NEW)】五、操作符详解(二) 一、表达式求值 1.1 隐式类型转换 1.1.1 什么是整型提升(整型提升) 1.1.2 整型提升的意义 1.1.3 有符号(signed)与无符号(unsigned)的区别 1.1.4 有符号(signed)类型的整型提升 1.1.5 无符号(unsigned)整形提升 1.1.6 整型提升例子 1.2 算术转换 1.3 操作符的属性 二、位操作符的一些例题 三、数据类型大小
【C语言初阶(NEW)】五、操作符详解(一) 一、操作符分类 二、算术操作符 三、移位操作符 3.1 移位操作符简介 3.2 原码、反码、补码 3.3 左移运算符 3.4 右移运算符 3.5 警告 四、位操作符 4.1 & 按位与 4.2 | 按位或 4.3 ^ 按位异或 五、赋值操作符 六、单目操作符 6.1 单目操作符介绍 6.2 ! 逻辑反操作符 6.3 - +(负值、正值) 6.4 ~ 取反 6.5 -- 运算符和 ++ 运算符 6.6 & 取地址和 * 解引用 6.7 sizeof 操作符 6.8 (类型) 强制类型转换 七、关系操作符 八、 逻辑操
C语言数据结构 | 堆栈顺序、链式存储及表达式求值 从计算机对表达式求值引入算数表达式在求值时若无优先级,那么从左到右运算就很容易,但算术表达式由两类对象构成一个是一个是+-*/······不同的运算符号优先级也不一样此时运算就比较困难 ,无法判断运算符后一个运算数是否参与这次运算。
异步社区 异步社区(www.epubit.com)是人民邮电出版社旗下IT专业图书旗舰社区,也是国内领先的IT专业图书社区,致力于优质学习内容的出版和分享,实现了纸书电子书的同步上架,于2015年8月上线运营。公众号【异步图书】,每日赠送异步新书。