2

在下面的代码片段中

int jo=50;
if( jo =(rand()%100), jo!=50)
{
    printf("!50");
}   
  1. % 具有最高优先级,因此 rand()%100 将首先执行
  2. != 的优先级大于 = 所以 jo != 50 应该得到执行吗?
  3. , 当我先执行赋值然后 != 然后 , 时,优先级仍然最低。我得到一个输出!50 为什么?
4

4 回答 4

4

问题是“序列点”:

http://www.angelikalanger.com/Articles/VSJ/SequencePoints/SequencePoints.html

有问题的与安全的表达

是什么导致赋值 x[i]=i++ + 1; 一个有问题的,而分配 i=2;是无害的,因为它的结果是明确定义和可预测的?关键在于表达式 x[i]=i++ + 1; 对变量 i 有两种访问,其中一种访问,即 i++,是一种修改访问。由于未定义序列点之间的评估顺序,我们不知道是否会在读取 i 之前对其进行修改,或者是否会在修改之前对其进行读取。因此,如果访问是修改,则问题的根源是对序列点之间的变量的多次访问。

这是另一个例子。如果在执行语句之前 i 和 j 的值分别为 1 和 2,这里会发生什么?

f(i++, j++, i+j); 

哪个值将作为第三个参数传递给函数 f?再说一次,我们不知道。它可以是以下任何一种:3、4 或 5。它取决于计算函数参数的顺序。
这里常见的误解是参数将从左到右进行评估。或者也许从右到左?事实上,语言定义没有规定任何顺序。

于 2012-05-26T05:29:16.530 回答
3

优先级不控制执行顺序。优先级只控制分组——也就是说,优先级说明每个操作的操作数是什么,而不是每个操作发生的时间。

在此示例中,由于括号的原因, 的优先级%无关紧要 - 这些表示 的操作数%rand()100

,低于=and的优先级!=告诉我们,操作数=joand (rand()%100),并且操作数!=joand 50

的操作数,是 thenjo = (rand() % 100)jo != 50

运算符的定义,说,第一个操作数被求值,然后有一个序列点,然后第二个操作数被求值。所以这种情况,jo = (rand() % 100)是完全评估的,它将结果存储rand() % 100jo; 然后jo != 50被评估。整体表达式的值是 的值jo != 50

于 2012-05-26T05:36:54.677 回答
3

好吧,序列点是正确的答案。但是让我们从教科书中翻译。

逗号运算符有一个特殊的属性:它确保首先评估其左侧的内容。所以,当你到达表达式时

 jo =(rand()%100), jo!=50

即使!= 绑定比 ',' 更紧密,所以完全括起来的表达式是

 (jo =(rand()%100)),(jo!=50)

首先评估第一部分。

要记住这一点,您可以将逗号运算符发音或读为“然后”,所以

 j0=(rand()%100)

“进而”

 jo!=50.
于 2012-05-26T05:37:15.263 回答
2

将“优先级”视为“先完成”是错误的。

考虑以下代码片段:

f() + g() + h()

哪个具有加法运算的优先级更高,一个是 f() 和 g() 的结果相加,还是那个和 h() 的结果相加?

这是一个棘手的问题,因为根本不需要调用“优先级”。但是仍然存在操作顺序,因为 C 中的函数调用引入了“序列点”,这就是 C 允许您确定“何时发生什么”的方式。

在您的特定代码中,您有一个逗号运算符 - 这与函数参数中的逗号标点符号完全不同 - 在这部分:

jo = (rand() % 100), jo != 50

逗号运算符引入了一个序列点(就像对 的函数调用一样rand),因此我们知道rand运行并产生一个值,然后% 100计算该值并将其分配给jo,最后jo与 进行比较50

(在评估控制表达式之后还有一个序列点if,并且在每个语句结束分号处都有一个。)

于 2012-05-26T05:35:58.843 回答