- 现代C:概念剖析和编程实践
- (德)延斯·古斯泰特
- 1101字
- 2025-04-08 00:44:17
4.1 算术
运算符表4.1中的算术运算符对值进行运算。
4.1.1 +、-
和*
算术运算符+
、-
和*
主要是用于分别计算两个值的和、差和乘积:

这里,c
等于76
,d
等于31
。从这个小示例中可以看到,子表达式可以与括号组合在一起,以实现对运算符的优先绑定。
此外,运算符+
和-
有一元变体。-b
给出b
的负值:值a
可以使b + a
等于0
。+a
只是提供了a
的值,下面的结果也是76
:

即使我们使用无符号类型来进行计算,通过运算符-
来求反和求差也是不错的定义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
的情况,范围是0
到SIZE_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小时。