整数类型变量是不包含分数的变量,如(-2,-1,0,1,2),C++有5种不同类型的整形变量可供使用:
Category | Type | Minimum Size | Note |
---|---|---|---|
character | char | 1 byte | |
integer | short | 2 bytes | |
int | 2 bytes | Typically 4 bytes on modern architectures | |
long | 4 bytes | ||
long long | 8 bytes | C99/C++11 type |
Char类型是一种比较特殊的类型,它可以同时作为整形和字符型使用,这个后面会详细讨论,本章中你只需要把它当成一个简单的整形就OK了。
上面的几种整形的不同之处就是size的不同,size越大,可存储的数据值也就越大。需要注意的是C++只是规定了整形变量的最小size,并不是特定的size,可以参照上一节内容。因此各种不同类型在你的机器上size可能是不同的。
定义整型数据类型:
定义一些整数:
char c;
short int si; // valid
short s; // preferred
int i;
long int li; // valid
long l; // preferred
long long int lli; // valid
long long ll; // preferred
虽然short int,long int,long long int的定义符是有效的,但是建议优先使用short,long,long long的定义方式。除了写起来更加简单之外,这样还会使这些变量与int类型可以比较好的区分开,同时如果无心漏写了long,short,我们会及时发现数据类型定义错误。
识别整型:
因为整型的size跟编译环境以及硬件电脑相关,那么使用变量,而不是名字来定义整型更加有效,如我们经常通过分配给变量的位数来识别整型类型,如32 bit数据替代long。
整型的范围和标志:
根据上一节的内容来看,n位size可以表示2的n次方个不同数据。但是这些是什么数据呢?我们称这系列特殊的数据教过整型的范围。整型的类型由两方面决定:1.size 2.符号(通常分为有符号和无符号数据)
signed标志该数据可以包含正数和负数两种类型,如下:
signed char c;
signed short s;
signed int i;
signed long l;
signed long long ll;
惯例来说,一般不会在前面写上signed类型。
1 byte size(8位)可以表示signed的数值是-127~128范围的数据。
有些时候我们并不需要负数,这样就需要unsigned的类型。比如需要存储size的大小,你的身高,体重不可能用复数。此时我们就可以使用unsigned的数值表示。
unsigned char c;
unsigned short s;
unsigned int i;
unsigned long l;
unsigned long long ll;
1 byte size可以存储的unsigned的数值是0~255范围的数据
可以看出来,无符号的数值,同等size下不能保存负数,但是正数的范围会扩大一倍。
既然你已经了解了signed和unsigned的不同,就请参考一下下面的数据范围:
Size/Type | Range |
---|---|
1 byte signed | -128 to 127 |
1 byte unsigned | 0 to 255 |
2 byte signed | -32,768 to 32,767 |
2 byte unsigned | 0 to 65,535 |
4 byte signed | -2,147,483,648 to 2,147,483,647 |
4 byte unsigned | 0 to 4,294,967,295 |
8 byte signed | -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807 |
8 byte unsigned | 0 to 18,446,744,073,709,551,615 |
对于数值来说,一般n位的size可以保存的signed数值的范围是:-(2的n-1次方)~ (2的n-1次方)-1;unsigned数值的方位就是2的n次方-1.
新手往往会把sign和unsign搞混。其实比较好区分,在需要区分正负的场合,我们就需要使用有符号的声明。而在只有正数的需求的时候,我们会使用unsigned的数据类型。
使用方法:
当你没有特别声明是否是有符号时:
Category | Type | Default Sign | Note |
---|---|---|---|
character | char | Signed or Unsigned | Usually signed |
integer | short | Signed | |
int | Signed | ||
long | Signed | ||
long long | Signed |
所有的数据类型都被默认为signed,char类型可以是signed或者unsigned,默认是signed。
通常来说signed字符是冗余不需要的,因为默认就是signed。
最好的使用方法就是除非由unsiged的需求,否则不需要定义unsigned变量。因为无符号变量可能会引起一些bug。
规则:优先选择有符号的整数类型
溢出:
当我们把一个数据类型范围之外的整数放到变量中,会发生什么情况呢?这个时候会产生溢出的问题,因为变量没有足够的空间来存储该变量。在2.1节中,我们提到了变量是以二进制存储的。
二进制数据中每一位都有两种可能,如下加入我们想要从0数到15,那么如下表所示:
Decimal Value | Binary Value |
---|---|
0 | 0 |
1 | 1 |
2 | 10 |
3 | 11 |
4 | 100 |
5 | 101 |
6 | 110 |
7 | 111 |
8 | 1000 |
9 | 1001 |
10 | 1010 |
11 | 1011 |
12 | 1100 |
13 | 1101 |
14 | 1110 |
15 | 1111 |
你可以看到越大的数会有越大的位数来存储,因为我们的变量需要固定的位数来表示,这就限制了他们能保存多大的数据。
溢出的例子:
但是假如我们想把一个超过4位的变量放到这个变量里会发生什么事情呢?这个时候就会溢出,变量只存储了右边4位,而不是完全存储。
比如我们想要把21放到4位的变量里:
Decimal Value | Binary Value |
---|---|
21 | 10101 |
这个时候我们只会得到0101,最前面的一位1就不见了。也就是存储了5这个数字。
在本章你不需要直到二进制和十进制怎么转换,我们在后面的3.7章节会详细讨论。
下面让我们以实际例子来看看数据溢出的问题,假设short类型时16位:
#include <iostream>
int main()
{
unsigned short x = 65535; // largest 16-bit unsigned value possible
std::cout << "x was: " << x << std::endl;
x = x + 1; // 65536 is out of our range -- we get overflow because x can't hold 17 bits
std::cout << "x is now: " << x << std::endl;
return 0;
}
你觉的结果应该是什么?
x was: 65535 x is now: 0
发生了什么?我们想把65536放到一个16位的变量中,但是65536二进制是17位的,10000000000000000,这个时候取右边16位,自然就是0了。
溢出导致了信息的丢失,这是非常不可取的。所以假如你要存储一个很大的变量,一定要尽可能大的使用相应的变量类型。
溢出结果只针对无符号整数,有符号的整数或者小数溢出后会有不同的结果,这个会根据不同的系统的情况而不同。
整数的除法:
当整数可以整除的时候,那么程序输出的结果和你预想的是一样的:
#include <iostream>
int main()
{
std::cout << 20 / 4;
return 0;
}
该程序会输出5.
但是当除法不能整除的时候看看:
#include <iostream>
int main()
{
std::cout << 8 / 5;
return 0;
}
这个程序的输出结果是:1
当两个整数做除法的时候,C++只能生成一个整数的结果,也就把小数部分直接丢掉了。如例子中8/5=1.6,但是程序算出来就是1,0.6直接丢掉。
小心使用整数的除法,因为会丢掉小数部分。