关于C语言中的复合赋值操作符

复合赋值操作符有 +=, -=, *=, /=,%=, <<=, >>=, &=, ^=, |=。

下面以+=为例

a += expression        (1)

等价于:

a = a + expression   (2)

但是,这里是有区别的,(1)式中的a(如数组下标访问的元素)只求值一次,(2)式中的a求值两次,当然编译器也许会优化,可能会使得(2)式效果和(1)式一样,但是有例外的情况,编译器是无法优化的。如:

int f(int x){return x;}
 
int a[10] = {0};
int x = 2;
 
a[f(x) + 1] += 1;              // (1)
a[f(x) + 1] = a[f(x) +1] +1;      // (2)

以上两个表达式机器代码是完全不同的,对于(2)式,由于是调用函数,编译器并不能确定每次函数都返回相同的值(即是否有副作用),所以编译器对此无能为力,不能对此优化,因此也就会去乖乖地调用两次函数,而(1)式只调用一次函数,参见VS2010下的汇编代码:

    a[f(x) + 1] = a[f(x) +1] +2;
013B1413  mov        eax,dword ptr [ebp-3Ch] 
013B1416  push       eax 
013B1417  call       @ILT+110(_f) (13B1073h) 
013B141C  add        esp,4 
013B141F  mov        esi,dword ptr [ebp+eax*4-2Ch] 
013B1423  add        esi,2 
013B1426  mov        ecx,dword ptr [ebp-3Ch] 
013B1429  push       ecx 
013B142A  call       @ILT+110(_f) (13B1073h) 
013B142F  add        esp,4 
013B1432  mov        dword ptr [ebp+eax*4-2Ch],esi 
    a[f(x) + 1] += 2;
013B1436  mov        eax,dword ptr [ebp-3Ch] 
013B1439  push       eax 
013B143A  call       @ILT+110(_f) (13B1073h) 
013B143F  add        esp,4 
013B1442  lea         ecx,[ebp+eax*4-2Ch] 
013B1446  mov        dword ptr [ebp-104h],ecx 
013B144C  mov        edx,dword ptr [ebp-104h] 
013B1452  mov        eax,dword ptr [edx] 
013B1454  add        eax,2 
013B1457  mov        ecx,dword ptr [ebp-104h] 
013B145D  mov        dword ptr [ecx],eax

因此,如果我们能确定表达式中不含有副作用的元素(如上面的函数f),那么我们应尽量使用复合赋值操作符,不失效率同时书写方便。

你可能感兴趣的:(c,赋值操作符)