4.4 - 有符号整型
Key Takeaway
- n 位有符号整型的范围为 \(-(2^{n-1})\) 到 \(2^{n-1}-1\)。
- 有符号整型的溢出会导致未定义行为
整型是一种整数类型,它可以表示正整数和负整数,当然也包括 0(例如:-2、-1、0、1、2)。C++ 中有 4 中基础整型:
Type | Minimum Size | Note |
---|---|---|
short | 16 bits | |
int | 16 bits | 现代计算机体系结构下通常为 32 位 |
long | 32 bits | |
long long | 64 bits |
这些类型的主要差异是它们的大小不同——越大的整型可以表示越大的数。
提醒
C++ 只保证整型占用空间的最小值,而不保证其具体值。请参考4.3 - 对象的大小和 sizeof 操作符来确定每种类型在你机器上的具体大小。
有符号整型
在日常生活中,如果我们要表示负整数,通常会使用负号。例如,-3 表示 “负三”。我们还会使用+3 来表示”正三“(尽管通常正号会被省略)。数字的这种“正负零”属性,称为数字的负号。
默认情况下,整型是有符号的,也就是说数字的符号是数字本身的一部分(使用一个位进行存储,称为符号位)。因此,有符号整型可以表示正数负数和 0。
在这节课中,我们会专注于介绍有符号整型(signed)。无符号(unsigned)整型(只能保存非负值)则会在后续的课程中进行讨论。
相关内容
我们在 O.4 -- Converting between binary and decimal 中讨论了二进制表示法时符号位如何使用。
定义有符号整型
定义有符号整型时,推荐的方式如下:
1 2 3 4 |
|
所有的整型(除了 int
)以外,都可以带上一个可选的 int
后缀:
1 2 3 |
|
不过,并不推荐使用这些后缀。使用这些后缀不仅需要打更多字,而且添加 int
后缀后,不容易将这些类型和 int
类型的变量区分开来,而且如果不经意忘记了 short
或者 long
修饰符的话则可能会引入问题。
整型还可以添加一个可选的 singed
关键字,通常会将其放置在类型名前:
1 2 3 4 |
|
不过,这个关键字也不推荐使用,因为它是多余的,整型默认就是有符号的。
最佳实践
使用最精简的写法,不要使用 int
后缀或 signed
前缀。
有符号整型的范围
正如之前介绍的那样,在内存中占用 n 位的变量,可以保存 \(2^n\) 个可能的值。但是,具体是哪些值呢?我们称一种类型可以表示的值为其范围。而整型的范围有两个因素决定:大小(多少位),是否有符号。
根据定义,8 位有符号整型可以表示的范围是:-128 到 127。也就是说一个有符号整型可以安全地表示 -128 到 127 (包括) 中的任意整数。
题外话
数学时间:8 位整型有 8 个位,2 的 8 次方是 256,所以它一共可以保存 256 个可能的值。在 -128 到 127 中一共有 256 个可能的整数值。
下表展示了不同有符号整型可以表示的范围:
大小/类型 | 范围 |
---|---|
8 bit signed | -128 到 127 |
16 bit signed | -32,768 到 32,767 |
32 bit signed | -2,147,483,648 到 2,147,483,647 |
64 bit signed | -9,223,372,036,854,775,808 到 9,223,372,036,854,775,807 |
对于喜欢数学表示法的人来说: n 位有符号整型的范围为 \(-(2^{n-1})\) 到 \(2^{n-1}-1\)。
对于不喜欢数学的人来说,参考上表就可以了。
整数溢出
如果我们尝试把 280 赋值给一个 8 位有符号整型会发生什么呢?这个数字已经超出了 8 位有符号整型数能够表示的范围。280 需要 9 个位(加一个符号位)才能表示,但是一个8位整型只有7个位(加一个符号位)。
当需要存储的值的范围超过了变量可以表示的范围,就会发生整数溢出(通常简称为溢出) 。这是因为我们需要表示的数,需要比该变量能够使用的更多的位。这种情况下,变量将没有足够的内存空间可以用来存放数据。
对于有符号整型来说,究竟哪个位的数据会被丢弃并没有明确的定义,因此有符号整型的溢出是未定义行为。
注意
有符号整型的溢出会导致未定义行为
通常来说,溢出会导致信息的丢失,这是我们最不希望发生的是。如果你怀疑对象需要保存的值有可能会超过它能够表示的范围,请使用范围更大的类型!
整型除法
当对两个整型进行除法运算时, 如果商是整数,则结果应该如你所料:
1 2 3 4 5 6 7 |
|
计算结果为 5。
但是,让我们看看这个商是小数的例子:
1 2 3 4 5 6 7 |
|
计算结果为 1。
当 C++对两个整型做除法时(称为整数除法),它只能产生整数结果,因为整型不能保存小数值,结果中的小数部分会被丢弃(而不是四舍五入)。
仔细看看上面的例子,8 / 5 应该等于1.6,但是小数部分(0.6)会被丢弃,所以结果为1。
同样的,-8 / 5 的结果为 -1。
注意
在使用整数除法时要小心,因为商中的小数部分会被丢弃。不过,如果这恰好是你期望的,那么可以放心使用。
如果你希望保留小数部分,请参考 5.2 - 数学运算符 中介绍的方法。