在C语言中,有你需要知道的两个不同的问题:运算符优先级和为了评估的。
运算符优先级决定哪个运算符获得首先评估的操作数,以及属于哪个运算符的哪些操作数。例如在表达式a + b * c
中,运算符*的运算符优先级高于+。因此,表达式将被评估为
a + (b * c)
在C语言中的所有运营商有确定性优先级,他们是在任何编译器是相同的。
评估顺序决定哪个操作数首先得到评估。请注意,子表达式也是一个操作数。评估顺序在运营商优先级确定后应用。如果上面的a + b * c示例具有从左到右的评估顺序,则操作数本身将按照a,b,c的顺序进行评估。如果操作数是例如函数调用,那么函数a(),b()和c()将按照该顺序执行。这个例子中的所有操作数都需要被评估,因为它们都被使用了。如果编译器可以确定某些操作数不需要进行评估,则可以优化它们,而不管这些操作数是否包含副作用(如函数调用)。
的问题是操作数的计算顺序是最常见的不确定的行为,这意味着编译器是免费的评估是左到右或从右到左,我们无法知道或承担任何事它。对于C中的大多数操作数来说,这是事实,除了评估顺序始终是确定性的一些例外。这些是运营商|| && ?: ,
的操作数,其中评估的顺序保证为从左到右。 (当使用正规的C语言的语义,一个说有左的评价和右操作间的时序点。)
所以对于具体的例子m = ++i || ++j && ++k
。
- 一元前缀++运算符的优先级最高,它们将运算符i,j和k绑定到它们。这个语法非常直观。
- 二进制& &运算符具有第二高的优先级,将运算符
++j
和++k
绑定到它。所以表达式相当于m = ++i || (++j && ++k)
。
- 二进制||运营商具有第三高优先级,将运营商
i++
和(j++ && ++k)=
绑定到它。
- 赋值操作符=具有最低的优先级,结合运营商
m
和++i || (++j && ++k)
到它。
此外,我们可以看到,无论是||并且运营商是保证评估顺序保持从左到右的那些运营商之一。换句话说,如果||的左操作数运算符被评估为true,编译器不需要评估正确的操作数。在具体的例子,++i
总是正的,所以编译器可以执行相当的优化,有效地改造了表达m = ++i;
如果i
值在编译时不知道,编译器会被强行评估整个表达。然后表达式将按此顺序进行了评价:
- & &比||优先级高,所以开始评估& &操作。
- & &操作者保证具有左到右操作数的评价顺序,因此首先执行++Ĵ。
- 如果++ j的结果为真(大于零),并且只有这样,则评估正确的运算符:perform ++ k。
- 商店++Ĵ& & ++ K的临时变量的结果。我在这里将其称为
j_and_k
。如果++ j和++ k都为正,则j_and_k
将包含值1(真),否则包含0(假)。
- ||运算符保证有操作数从左到右的评估顺序,所以先执行++ i。
- 如果++ i是假(零),也只有这样,评估右操作“
j_and_k
”。如果其中一个或两个都是肯定的,则||的结果运算符为1(真),否则为0(假)。
- m取决于结果获取值1或0。
哦,不,不会再 –
这是一个常见的问题功课这些天? – crashmstr