这个表达式将如何在C中进行评估?

时间:2017-01-13 17:40:47

标签: c printf

我无法弄清楚如何在C中评估此表达式? 我对printf中的表达式的评估有点困惑? 如果printf中的表达式从右到左进行评估,那么表达式的评估应该在遇到(c> 10)之后停止,但它会在输出屏幕上打印“1”?

这不是C的确切语法,而是向我询问的一个问题。

integer a = 50, b = 25, c = 0;
printf( a > 45 || b > 50 && c > 10 );

4 个答案:

答案 0 :(得分:2)

此表达式

a > 45 || b > 50 && c > 10

相当于表达式

( a > 45 ) || ( b > 50 && c > 10 )

因此,如果此子表达式( a > 45 )的计算结果为true,则第二个子表达式将不会计算,结果等于1(类型为int)。

否则此子表达式

( b > 50 && c > 10 )

相当于

( b > 50 ) && ( c > 10 )

如果( b > 50 )的计算结果为false,则整个结果为false(C中为0),第二个子表达式将不会计算。否则结果是值 子表达式c > 10。如果是c > 10,那么结果是int类型为1的对象,如果不是( c > 10 ),则结果的值为0.

如果变量具有问题中显示的值

int a = 50, b = 25, c = 0;

然后是第一个子表达式

a > 45

计算结果为true,结果为int类型1。第二个子表达式

b > 50 && c > 10

甚至不会评估。

考虑以下示范程序

#include <stdio.h>

int f( int x )
{
    printf( "f is called for %d\n", x );
    return x;
}

int main( void ) 
{
    int a = 50, b = 25, c = 0;

    f( f( a ) > 45 || f( b ) > 50 && f( c ) > 10 ); 

    return 0;
}

它的输出是

f is called for 50
f is called for 1

正如您所看到的,计算表达式f( a ) > 45就足以使结果等于1

答案 1 :(得分:1)

这将是未定义的行为。 printf的第一个参数必须是格式字符串。最有可能它会崩溃。拯救你的是“整数”不是一个类型,所以它不会编译。

答案 2 :(得分:1)

||&&运营商都强制进行从左到右的评估。在评估右侧操作数之前,将对左侧操作数进行全面评估(并应用所有副作用)。

此外,两个运算符短路 - 根据左侧操作数的值,可能根本不会评估右侧操作数。

有关

a || b

如果a为真,那么无论b的值如何,整个表达式都为真,因此不会评估b

同样,

a && b

如果a为false,则无论b的值是什么,整个表达式都为false,因此不会评估b

&&的优先级高于||,因此

a || b && c 

将被解析为

a || (b && c)

a && b || c 

将被解析为

(a && b) || c  

因此...

a > 45 || b > 50 && c > 10

被解析为

a > 45 || (b > 50 && c > 10 )

a == 50以来,a > 45为真。由于a > 45||运算符的左侧操作数,因此无论右侧操作数如何,整个表达式都为true,因此根本不会计算b > 50 && c > 10

表达式的结果是1(真)。

不幸的是,printf期望其第一个参数指向字符串(格式字符串),而1很可能不是您平台上的有效地址,因此此代码的结果将是很可能是一个段错误。简单的解决方法是编写

printf( "%d\n", a > 45 || b > 50 && c > 10 );

答案 3 :(得分:0)

表达式出现的上下文会影响是否评估它,而不是如何。评估较大表达式的子表达式的顺序由operator precedence and associativity控制。

在您的表达式中的运算符中,>具有最高优先级,然后是&&,然后是||。所有员工从左到右。因此,您的表达式的计算方式与它的编写方式完全相同:

(a > 45) || ((b > 50) && (c > 10))

此外,&&||运算符执行短路评估。这对你来说似乎是一个混乱点。短路评估意味着如果&&||操作的结果由左侧操作数的值确定,则该操作的右侧操作数 未评估。这不会影响是否或如何评估其他操作,除非将短路操作的结果用作操作数。

但是,在这种情况下,由于||从左到右关联,因此首先评估a > 45,生成1(true)。因为这决定了||操作的结果,所以不评估其右侧操作数。相对运算符优先级产生右侧操作数是整个表达式的其余部分,如上所示,因此不会对其进行评估。但是,即使 进行了评估,整个表达式的结果仍然是1,因为左侧操作数的计算结果为1,而不管右手子的表达。这就是为什么||的右侧不需要评估的原因。