有符号整数
本节阅读量:整数是可以表示正整数和负整数(包括0)的整型类型(例如-2、-1、0、1、2)。C++有4种主要的基本整数类型可供使用:
| 类型 | 最小大小(字节) | 注 |
|---|---|---|
| short int | 2 | |
| int | 2 | 现代机器上通常是4个字节 |
| long int | 4 | |
| long long int | 8 |
不同整数类型之间的关键区别在于大小不同——较大的整数类型可以表示更大的数字。
一个提醒
C++只保证整数具有特定的最小大小,而不保证具有确切的大小。有关如何确定每种类型在你机器上的实际大小,请参见前一节的sizeof运算符。
旁白
严格来说,bool和char类型也被视为整型(因为它们的值以整数形式存储)。在接下来的几节课中,我们将暂不讨论这些类型。
有符号整数
在日常生活中书写负数时,我们使用负号。例如,-3表示”负3”。我们通常也能识别+3为”正3”(尽管按照惯例,正号通常会被省略)。
正、负或零的属性称为数字的符号。
默认情况下,C++中的整数是有符号的,这意味着数字的符号存储为数字的一部分。因此,有符号整数可以同时包含正数和负数(和0)。
在本课中,我们将重点讨论有符号整数。在下一课中,我们将讨论无符号整数(它只能容纳非负数)。
相关内容
在二进制表示中,使用单个比特(称为符号位)来存储数字的符号。其余的非符号位用于表示数字的大小。
定义有符号整数
下面是定义四种类型的有符号整数的首选方法:
|
|
尽管short int、long int或long long int也能正常使用,但我们更推荐使用这些类型的简写形式(不带int后缀)。添加int后缀会使这些类型更难与int类型的变量区分开来。如果不小心遗漏了short或long修饰符,就可能引发错误。
整数类型也可以加上可选的signed关键字,按照惯例放在类型名称之前:
|
|
然而,不应该使用该关键字,因为它是多余的——整数默认就是有符号的。
最佳实践
优先使用不带int后缀和signed前缀的有符号整数类型。
有符号整数范围
正如你在上一节中了解到的,一个n位的变量可以保存2的n次方个可能的值。但具体能表示哪些值呢?整数变量的取值范围由两个因素决定:它的大小(以位为单位)和它是否有符号。
根据定义,8位有符号整数的范围是-128到127。这意味着有符号整数可以安全地存储-128到127(含)之间的任何整数值。
下面是不同大小的有符号整数的取值范围表:
| 类型大小 | 取值范围 |
|---|---|
| 8位 | -128 to 127 |
| 16位 | -32,768 to 32,767 |
| 32位 | -2,147,483,648 to 2,147,483,647 |
| 64位 | -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807 |
用数学公式来表示,n位有符号变量的范围为-2^(n-1)到2^(n-1)-1。
旁白
来算一下:8位整数包含8个比特。2^8等于256,因此8位整数可以容纳256个不同的值。从-128到127恰好有256个值(含两端)。
其中7位用于表示数字的大小,1位用于表示符号。
溢出(Overflow)
如果尝试将值140赋给8位有符号整数,会发生什么?这个数字超出了8位有符号整数所能容纳的范围。数字140需要9位来表示(8个量值位和1个符号位),但8位有符号整数只有8位可用(7个量值位和1个符号位)。
C++20标准对此有一条总括性声明:”如果在表达式求值过程中,结果在数学上未定义,或者不在其类型的可表示值范围内,则行为是未定义的。”通俗地说,这就是所谓的溢出。
因此,将值140分配给8位有符号整数将导致未定义的行为。
如果算术运算(如加法或乘法)产生的结果超出了可表示的范围,就称为整数溢出(或算术溢出)。对于有符号整数,整数溢出会导致未定义行为。
通常,溢出会导致信息丢失,这几乎总是不可取的。如果你怀疑某个对象可能需要存储超出其范围的值,请使用取值范围更大的类型!
整数除法
对两个整数进行除法时,如果结果恰好是整数,C++的运算结果与预期一致:
|
|
这会产生预期的结果:
|
|
但让我们看看当整数除法的结果包含小数部分时会发生什么:
|
|
这可能产生出乎意料的结果:
|
|
对两个整数进行除法(即整数除法)时,C++始终产生整数结果。由于整数无法保存小数部分,任何小数部分都会被直接丢弃(注意是截断,不是四舍五入!)。
仔细看上面的例子,8/5的精确值为1.6。丢弃小数部分(0.6)后,结果为1。换一种说法,8/5等于1余3,余数被丢弃,只保留1。
类似地,-8/5产生值-1。
如果需要得到带小数的结果,我们将在后续课程中介绍具体做法。
警告
使用整数除法时要小心,因为结果中的小数部分会被丢弃。当然,如果你不需要小数部分,那么整数除法是安全的,因为结果是可预测的。