在下面的代码片段中
int jo=50;
if( jo =(rand()%100), jo!=50)
{
printf("!50");
}
- % 具有最高优先级,因此 rand()%100 将首先执行
- != 的优先级大于 = 所以 jo != 50 应该得到执行吗?
- , 当我先执行赋值然后 != 然后 , 时,优先级仍然最低。我得到一个输出!50 为什么?
在下面的代码片段中
int jo=50;
if( jo =(rand()%100), jo!=50)
{
printf("!50");
}
问题是“序列点”:
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。它取决于计算函数参数的顺序。
这里常见的误解是参数将从左到右进行评估。或者也许从右到左?事实上,语言定义没有规定任何顺序。
优先级不控制执行顺序。优先级只控制分组——也就是说,优先级说明每个操作的操作数是什么,而不是每个操作发生的时间。
在此示例中,由于括号的原因, 的优先级%
无关紧要 - 这些表示 的操作数%
是rand()
和100
。
,
低于=
and的优先级!=
告诉我们,操作数=
是jo
and (rand()%100)
,并且操作数!=
是jo
and 50
。
的操作数,
是 thenjo = (rand() % 100)
和jo != 50
。
运算符的定义,
说,第一个操作数被求值,然后有一个序列点,然后第二个操作数被求值。所以这种情况,jo = (rand() % 100)
是完全评估的,它将结果存储rand() % 100
到jo
; 然后jo != 50
被评估。整体表达式的值是 的值jo != 50
。
好吧,序列点是正确的答案。但是让我们从教科书中翻译。
逗号运算符有一个特殊的属性:它确保首先评估其左侧的内容。所以,当你到达表达式时
jo =(rand()%100), jo!=50
即使!=
绑定比 ',' 更紧密,所以完全括起来的表达式是
(jo =(rand()%100)),(jo!=50)
首先评估第一部分。
要记住这一点,您可以将逗号运算符发音或读为“然后”,所以
j0=(rand()%100)
“进而”
jo!=50.
将“优先级”视为“先完成”是错误的。
考虑以下代码片段:
f() + g() + h()
哪个具有加法运算的优先级更高,一个是 f() 和 g() 的结果相加,还是那个和 h() 的结果相加?
这是一个棘手的问题,因为根本不需要调用“优先级”。但是仍然存在操作顺序,因为 C 中的函数调用引入了“序列点”,这就是 C 允许您确定“何时发生什么”的方式。
在您的特定代码中,您有一个逗号运算符 - 这与函数参数中的逗号标点符号完全不同 - 在这部分:
jo = (rand() % 100), jo != 50
逗号运算符引入了一个序列点(就像对 的函数调用一样rand
),因此我们知道rand
运行并产生一个值,然后% 100
计算该值并将其分配给jo
,最后jo
与 进行比较50
。
(在评估控制表达式之后还有一个序列点if
,并且在每个语句结束分号处都有一个。)