在本书的第4章“复合赋值:第二节C编程:现代方法”部分中,说:
请注意,我一直在注意不要说
v += e
与v = v + e
“等效”。一个问题是运算符优先级:i * = j + k
与i = i * j + k
不同。
我编写了一个程序来比较i * = j + k
和i = i * j + k
。
但是结果是一样的。
#include <stdio.h>
int main() {
int i = 1;
int j = 2;
i *= j + 10;
int k = 1;
k = k * j + 10;
printf("j=%d k=%d\n", i, k);
}
j = 12 k = 12
所以我的问题是:为什么i * = j + k
与i = i * j + k
不同?
感谢所有答复。我误解了复合赋值运算符。而且我写了一个误导性的测试。 我想说的是,你们很高兴讨论技术问题并一起学习。在中国找不到如此出色的网站和像您这样的人。
答案 0 :(得分:6)
如果您感到困惑,请看看operator precedence chart
就您而言,
i *= j + 10;
与
相同i *= (j + 10);
与
相同i = i * (j + 10);
但是
k = k * j + 10;
与
相同k = (k * j) + 10;
根据输出:尝试不同的值。
例如,如果我选择i
和k
作为2
,则输出将为
i = 24 k = 14
答案 1 :(得分:2)
简短回答:
很明显,它们指的是运算符优先级。那就是:
public class MyScrollView extends ScrollView {
static final int CONST_THUMB = 100; // thumb height
float divider = 1;
public MyScrollView(Context context) {
super(context);
}
@Override
public int computeVerticalScrollExtent() {
int length = computeVerticalScrollRange() -
super.computeVerticalScrollExtent();
if(length > 0)
divider = (float )(computeVerticalScrollRange() -
CONST_THUMB)/(float )length;
else
return super.computeVerticalScrollExtent();
return CONST_THUMB;
}
@Override
public int computeVerticalScrollOffset() {
return (int )((float )super.computeVerticalScrollOffset() * divider);
}
}
等效于i = i * j + k
。 i = (i * j) + k
等同于i *= j + k
。现在当然,如果使用i = i * (j + k);
之类的错误输入,那么运气不好,这两个表达式的结果将相同。不是因为C语言,而是因为小学数学。
(如果您是初学者,可以在这里停止阅读)
关于赋值运算符等效性的高级答案:
复合分配(i=1, j=1, k=1
)与简单分配*=
并不完全等效。标准C17 6.5.16.2说:
E1 op = E2 形式的化合物赋值等效于简单赋值表达式 E1 = E1 操作(E2),只是左值 E1 仅计算一次
意味着如果读取操作数E1会产生副作用,则复合赋值不同于简单赋值。考虑这个人为但有效的示例:
=
int foo (void)
{
static int n=0;
return ++n;
}
int array[3] = {1,2,3};
int* ptr = array;
#define FOO *(ptr + foo())
给出了一个数组FOO += 1;
,但是1 3 3
可以给出了一个数组FOO = FOO + 1;
1)。这是因为在后一种情况下会产生额外的副作用。
1)左FOO和右FOO之间的评估顺序未指定,因此可以给出不同的结果-这是未指定的行为。