4.1 算术

运算符表4.1中的算术运算符对值进行运算。

4.1.1 +、-和*

算术运算符+-*主要是用于分别计算两个值的和、差和乘积:

048-01

这里,c等于76d等于31。从这个小示例中可以看到,子表达式可以与括号组合在一起,以实现对运算符的优先绑定。

此外,运算符+-有一元变体。-b给出b的负值:值a可以使b + a等于0+a只是提供了a的值,下面的结果也是76

048-02

即使我们使用无符号类型来进行计算,通过运算符-来求反和求差也是不错的定义C。也就是说,不管我们输入到这样的减法中的值是多少,我们的计算总是会得到一个有效的结果。事实上,size_t的一个神奇的属性是,+-*运算总是可以在它所在的地方正常工作。只要最终的数学结果在[0,SIZE_MAX]范围内,那么这个结果就是表达式的值。

要点4.2 无符号算术总是定义良好的。

要点4.3 如果可以表示为size_t,则对size_t执行+-*操作可以提供正确的数学结果。

当结果不在该范围内,因此不能表示为size_t值时,我们称之为算术溢出C。例如,如果我们将两个非常大的值相乘,使它们的数学乘积大于SIZE_MAX,就会发生溢出。我们将在下一章中看到C是如何处理溢出的。

4.1.2 除法和余数

运算符/%稍微复杂一些,因为它们对应整数除法和余数运算。你可能对它们不像对其他三个算术运算符那样熟悉。a / b计算a相对b的倍数,a%b是刨去a相对b的最大倍数后的余数。运算符/%成对出现:如果z = a / b,余数a % b可以计算为a - z*b

要点4.4 对于无符号值,a==(a/b)*b+(a%b)

%运算符的一个常见例子是时钟上的小时。假设我们有一个12小时制的时钟:8点后6小时是2点。大多数人都能在12小时制或24小时制的时钟上计算时间差。此计算对应于a%12:在我们的例子中,(8 + 6)% 12 == 2[练习1]%的另一个类似用法是使用分钟来计算小时,形式为a % 60

只有一个值不允许用于这两个操作:0。禁止除以0

要点4.5 只有当第二个操作数不为0时,无符号/%才是定义良好的。

%运算符还可以更好地解释无符号类型的加法运算和乘法运算。如前所述,当给无符号类型赋予超出其范围的值时,这称为溢出C。在这种情况下,结果会减少,就像使用了%运算符一样。结果值“围绕”类型的范围。在size_t的情况,范围是0SIZE_MAX,因此

要点4.6 对size_t的运算隐含的意思是计算%(SIZE_MAX+1)

要点4.7 在溢出的情况下,无符号运算会围绕。

这意味着对于size_t值,SIZE_MAX + 1等于0,而0 - 1等于SIZE_MAX

这种“围绕”是使-运算符适用于无符号类型的魔力。例如,被解释为size_t的值-1等于SIZE_MAX,因此,将-1添加到值a时,就等于a + SIZE_MAX,该值被包装为

a + SIZE_MAX - (SIZE_MAX+1) = a - 1

运算符/%有一个很好的属性,其结果总是小于或等于它们的操作数:

要点4.8 无符号/%的结果总是比操作数小。

因此

要点4.9 无符号/%不能溢出。


[练习1]使用24小时制时钟进行一些计算,比如10:00点后3小时和20:00点后8小时。