目录
前言
优先级
结合性
是否控制求值顺序
问题表达式
一、
二、
三、
前言
复杂表达式的求值有三个影响的因素。
- ?操作符的优先级
- ?操作符的结合性
- ?是否控制求值顺序
? ? ?两个相邻的操作符先执行哪个?取决于他们的优先级。如果两者的优先级相同,取决于他们的结合性。
优先级
相邻的两个操作符才考虑优先级!
此处我们(下表)知道" * "优先级大于" + ":
?所以此处是" + "与" * "相邻," * "优先级高,先算" * "。
结合性
相邻的两个操作符的优先级一样时,先算什么就是结合性说的算!
?此处我们(下表)知道加法的结合性,是从左到右:
此处二者优先级相同,所以是从左到右计算,先" a "再" b "再" 2 "。
?当相邻操作符的优先级不同的情况下,优先级先起作用;优先级相同的情况下,那这个时候的结合性起作用。
是否控制求值顺序
这个是十分特殊的,只有少部分几个为是。(以" && "与" || "为例)
?我们按照心中常理分析,会感觉应该输出为a = 1 b = 3 c = 3 d = 5。但是其真实的输出为:
这就是因为其是会控制求值顺序的!
我们知道" && "是错一个即为错," || "是对一个即为对。此处的" && "的第一个是为后置++,先使用时a = 0,即为错,既然已经有一个错误了,那后面为什么都已经没有了必要,所以后面将不会再进行计算,这也就只是执行了" a++ "。这控制了求值顺序!
注:优先级和结合性,只决定运算符和哪些操作数结合和求值顺序毫无关系。
建议:
? ? ? ?我们这地方也没有必要特别刻意的把这个优先级啊,全部背下来,没什么大问题,没什么用啊,实际上呢,我们正在写的过程,实在没法拿捏的准时,查一下表,实在是懒了,都不想查的时候,你把它给括号一下,括号明确的时候就可以解决优先级问题。
从上到下优先级,由高到低
? ? ?操作符 | ? ? 描述 | ? ? ? ? ? ?用法示例 | ? ?结果类型 | ? ? ?结合性 | 是否控制求值顺序 |
---|
( ) | 聚组 | ( 表达式 ) | 与表达式同 | 无 | 否 | ( ) | 函数调用 | 函数名 (形参表) | 表达式 | 左到右 | 否 | [ ] | 下标引用 | 数组名 [常量表达式] | 变量 | 左到右 | 否 | . | 访问结构成员 | 对象 . 成员名 | 变量 | 左到右 | 否 | -> | 访问结构指针成员 | 对象指针 -> 成员名 | 变量 | 左到右 | 否 | ++ | 后缀自增 | 变量名 ++ | 表达式 | 右到左 | 否 | -- | 后缀值减 | 变量名 -- | 表达式 | 右到左 | 否 | ?! | 逻辑反 | ! 表达式 | 表达式 | 右到左 | 否 | ~ | 按位取反 | ~ 表达式 | 表达式 | 右到左 | 否 | + | 单目,表示正数 | + 表达式 | 表达式 | 右到左 | 否 | - | 单目,表示负数 | - 表达式 | 表达式 | 右到左 | 否 | ++ | 前缀自增 | ++ 变量名 | 表达式 | 右到左 | 否 | -- | 前缀自减 | -- 变量名 | 表达式 | 右到左 | 否 | * | 间接访问 | * 指针变量 | 变量 | 右到左 | 否 | & | 取地址 | & 变量名 | 表达式 | 右到左 | 否 | sizeof | 取其长度,以字节表示 | sizeof (表达式) | 表达式 | 右到左 | 否 | (类型) | 类型转换 | (数据类型) 表达式 | 表达式 | 右到左 | 否 | * | 乘法 | 表达式 * 表达式 | 表达式 | 左到右 | 否 | / | 除法 | 表达式 / 表达式 | 表达式 | 左到右 | 否 | % | 整数取余 | 整型表达式 % 整型表达式 | 表达式 | 左到右 | 否 | + | 加法 | 表达式 + 表达式 | 表达式 | 左到右 | 否 | - | 减法 | 表达式 - 表达式 | 表达式 | 左到右 | 否 | << | 左位移 | 变量 << 表达式 | 表达式 | 左到右 | 否 | >> | 右位移 | 变量 >> 表达式 | 表达式 | 左到右 | 否 | > | 大于 | 表达式 > 表达式 | 表达式 | 左到右 | 否 | >= | 大于等于 | 表达式 >= 表达式 | 表达式 | 左到右 | 否 | < | 小于 | 表达式 < 表达式 | 表达式 | 左到右 | 否 | <= | 小于等于 | 表达式 <= 表达式 | 表达式 | 左到右 | 否 | == | 等于 | 表达式 == 表达式 | 表达式 | 左到右 | 否 | != | 不等于 | 表达式 != 表达式 | 表达式 | 左到右 | 否 | & | 位与 | 表达式 & 表达式 | 表达式 | 左到右 | 否 | ^ | 位异或 | 表达式 ^ 表达式 | 表达式 | 左到右 | 否 | | | 位或 | 表达式 | 表达式 | 表达式 | 左到右 | 否 | && | 逻辑与 | 表达式 && 表达式 | 表达式 | 左到右 | 是 | || | 逻辑或 | 表达式 || 表达式 | 表达式 | 左到右 | 是 | ? : | 条件操作符 | 表达式1 ? 表达式2 :? 表达式3 | 表达式 | 无 | 是 | = | 赋值 | 变量 = 表达式 | 表达式 | 右到左 | 否 | += | 以…加 | 变量 += 表达式 | 表达式 | 右到左 | 否 | -= | 以…减 | 变量 -= 表达式 | 表达式 | 右到左 | 否 | *= | 以…乘 | 变量 *= 表达式 | 表达式 | 右到左 | 否 | /= | 以…除 | 变量 /= 表达式 | 表达式 | 右到左 | 否 | %= | 以…取模 | 变量 %= 表达式 | 表达式 | 右到左 | 否 | <<= | 以…左移 | 变量 <<= 表达式 | 表达式 | 右到左 | 否 | >>= | 以…右移 | 变量 >>= 表达式 | 表达式 | 右到左 | 否 | &= | 以…与 | 变量 &= 表达式 | 表达式 | 右到左 | 否 | ^= | 以…异或 | 变量 ^= 表达式 | 表达式 | 右到左 | 否 | |= | 以…或 | 变量 |= 表达式 | 表达式 | 右到左 | 否 | , | 逗号 | 表达式 , 表达式 , … | 表达式 | 左到右 | 是 |
? ? ? ?但是,即使具有优先级,结合性,是否控制求值顺序。表达式是无法确定唯一的计算路径的!于是就会出现一些问题表达式!
问题表达式
无法确定所写的代码的唯一计算路径的,那这个代码就是问题代码!
一、
? ? ? ?在计算的时候,由于" * "比" + "的优先级高,只能保证," * "的计算是比" + "早,但是优先级并不能决定第三个" * "比第一个" + "早执行(他们之间是不相邻的,无法利用优先性)。当abcdef为表达式时,不确定的多路径计算会带来不同的答案!(例如:分别都引用了一个变量" x ",就会导致谁先引用," x "先变为什么,然后再被引用。)
二、
? ? ? ?" c + --c "就是一个问题代码,虽然我们知道" 前置-- "与" + "优先级是前者大于后者,但是,这还是一个问题代码,因为我们根本无法知道前者c是什么时候准备好的,很可能减后猜准备,有可能还未减时才准备。(这就是随编程器所定的了,所以,其并不是只有一个计算路径。)
类似于上者的代码(资料来源与《C与指针》)
?如此多的编译器答案都大大不同!
三、
? ? ? 我们能通过操作符的优先级得知:先算乘法, 再算减法。但是,函数的调用先后顺序无法通过操作符的优先级确定。
如果,按照顺序调用函数:
- (2——3——1)那就是:4 - 2 - 3 = -2;
- (1——2——3)那就是:2 - 3 * 4 = -10;
- ……
这是无法确定唯一路径的。(毕竟,函数什么时候调用是没有标准的。)
|