3.2 认识复合赋值
接下来,我们继续修改cusum函数。这次主要针对while语句的循环体,目标是让它变得简洁。简单的语句和表达式不但看起来清爽,也能少打字,何乐而不为。下面就是修改之后的cusum函数。
unsigned long long int cusum(unsigned long long int r) { unsigned long long int n = 1, sum = 0; while(n <= r) { sum += n; n += 1; } return sum; }
观察一下,你会发现组成循环体的两条语句和以前不一样,变短了,没有了运算符+和运算符=,代之以新的运算符+=。尽管如此,这两条新语句依然是表达式语句,依然是由表达式和分号组成的。
运算符“=”仅仅是将其右操作数的值赋给左操作数,所以称为“简单赋值”。新的运算符+=用来取代原先的“=”和“+”,但综合了它们的语义,所以它既执行相加操作,也执行赋值操作,故称为复合赋值运算符。注意,复合赋值运算符+=的“+”和“=”必须连写,不能分开。
复合赋值运算符有很多种,“+=”只是其中之一,其他复合赋值运算符将在本书的后面接触到。和简单赋值运算符一样,复合赋值运算符也需要一左一右两个操作数,而且它的左操作数必须是左值,但并不执行左值转换。
表达式sum += n等价于表达式sum = sum + n,但是在语义上并不一样。前者是将变量n的值加到变量sum,对变量sum只操作一次(只需要一条将变量n的值加到变量sum的机器指令或者汇编语言指令);后者是读取变量sum和n的值相加后再保存到变量sum,对变量sum操作两次(需要先读变量sum的值,再保存新值到变量sum,这需要两条机器指令或者汇编语言指令)。
C语言规定,复合赋值运算符的左操作数必须是一个左值,但不执行左值转换,而是用于接受赋值。所有表达式都有值,复合赋值表达式也不例外,它的值是复合赋值运算符的左操作数被赋值之后的新值。这就是说,表达式sum += n的值是左值sum被赋值之后的新值。
在第1章里我们已经讲过副作用,有句俗话叫“搂草打兔子”,套用在这里一点都不为过。你看,我们本来是要计算表达式的值,还顺带把变量的值也给改了,这就是副作用。简单赋值表达式有副作用,复合赋值表达式也有副作用,它们都会修改变量的存储值。例如在表达式sum += n里,变量sum的值就被修改为它原来的值和变量n的值相加的结果。
同理,表达式n += 1等价于表达式n = n + 1。不同之处在于,n += 1中的n不执行左值转换,而仅仅是将1加到变量n并覆盖它原来的值。因此,n += 1也是有副作用的表达式。