数据加算法构成了我们通常所说的程序。数据作为程序的基本元素之一,其所包含的内容也是极其丰富的。为了更好的操作这些数据,就要对数据进行分类,这就引进了数据类型的概念。面向对象编程的本质是设计并扩展数据类型,而在这之前,我们必须了解C++的内置数据类型,然后在由此为基础设计新的数据类型。
1.C++内置数据类型分类
C++的内置数据类型包括基本类型和复合类型,基本类型也即我们平时常见的整型和浮点型;复合类型包括数组、字符串、指针和结构体等。
-
2.整型
类型 | 长度(位) | 典型值(64位win10) | 范围 |
bool | 8 | 8 | true/false |
char | 8 | 8 | -128到127或者0到255 |
signed char | 8 | 8 | -128 到 127 |
unsigned char | 8 | 8 | 0 到 255 |
short | 至少16位 | 16 | -32768 到 32767 |
unsigned short | 至少16位 | 16 | 0 到 65,535 |
int | 至少与short一样长 | 32 | -2147483648到2147483647 |
unsigned int | 至少与short一样长 | 32 | 0到4294967295 |
long | 至少32位,且至少与int一样长 | 32 | -2147483648到2147483647 |
unsigned long | 至少32位,且至少与int一样长 | 32 | 0到4294967295 |
long long | 至少64位,且至少与long一样长 | 64 | -9,223,372,036,854,775,808到 9,223,372,036,854,775,807 |
unsigned long long |
| 64 | 0到18,446,744,073,709,551,615 |
wchart_t | 16或32 | 16 | 1 个宽字符 |
char16_t | 16 | 16 | 1 个宽字符 |
char32_t | 32 | 32 | 1 个宽字符 |
特别说明:
1. char是一种特殊的整型,它用来存储字符。操作系统涉及的字符包括字母数字标点符号等等,而且总量一般不超过128个,比如常见的ASCII字符集。因此它的范围够用。当然,char也可以用来存储比short更小的整形数据。C++用单引号表示字符,用双引号表示字符串。所以,char类型的复制应该用单引号。
2. 通常意义上,用字节表示计算机的内存度量单位,也即1字节为8bit。但C++的字节是指至少能够容纳实现的基本字符集的相邻位组成。所以对于通常的使用ASCII字符集的系统来说,是1字节=8bit,但是国际编程领域,比如用到Unicode字符集的系统,1字节可能为16bit或32bit。
3.C++标准在规定长度时并没有写死某一类型的长度,它是以表格中的“至少”这种字样描述的。因此每个类型的长度会因为操作系统不同而发生变化。
4.各种整型类型都可以分为有符号型(signed)和无符号型(unsigned)。但通常short、int、long等没有关键字约束的,默认为signed;而要表示无符号数要加上unsigned, 如unsigned int。
5.加入你想查看自己系统下的各类型长度,可以调用sizeof函数获取长度,并打印出来。如:
cout<<"The size of bool is "<<sizeof(bool)<<endl; //输出流
cout<<"The size of char is "<<sizeof(char)<<endl; //输出流
cout<<"The size of short is "<<sizeof(short)<<endl; //输出流
cout<<"The size of int is "<<sizeof(int)<<endl; //输出流
cout<<"The size of long is "<<sizeof(long)<<endl; //输出流
cout<<"The size of long long is "<<sizeof(long long)<<endl; //输出流
cout<<"The size of wchar_t is "<<sizeof(wchar_t)<<endl; //输出流
6.变量的定义要对变量进行初始化,这很必要。不然该变量可能是个无法预料的数。因为未被初始化的变量会是该变量名所在的地址存放的数,而且这个数无法预估,我们可以认为是乱码。
7.如果遇到了一个常量,比如45,编译器如何知道它是哪个类型呢?如果开发人员不指定,系统会默认为int,因为int是处理最快的类型。当然,如果一个常量的值大于int能表示的范围,系统会自动用long或long long存储它。如果开发人员想自定义常量类型,可以用后缀表示。后缀L/l表示long,u表示unsigned。后缀的表示方法在整形数据中比较少。但是在浮点型数据中较为常见。比如用f/F表示float,用L/l表示double。
8.bool类型把非零数解释为true,把零解释为false;字面值true将被理解为1,字面值false被理解为0。
9.wchar_t是用于char不够表示字符集的情况,如应用Unicode字符集的系统。C++用前缀“L”来表示wchar_t类型常量。char16_t和char32_t是C++11引入的新的字符类型,源于wchar_t都不够用的字符集。前者为16位,后者为32位。
3.浮点类型
类型 | 长度(位) | 典型值 (64位win10) | 有效数字位数 |
float | 至少32 | 32 | 6位或7位 |
double | 至少48 | 64 | 15或16位 |
long double | 至少和double一样多,80/96/128 | 96 |
|
特别说明
1.系统是以基准值+缩放因子的方式存储浮点数的。类似于科学计数法,但缩放因子的底数不是10,而是2.
2.可以用e或E表示浮点数。如2.34e5 3.56E-6等
3.要注意在运算过程中的数据类型,以及数据类型转换时可能导致的而数据精度丢失。我们常说存在截断误差,即是在数据类型由长到段转换时导致的。所以double到float或int的转换要尤为小心。
4.在进行数学运算时,可以在常量后添加后缀以表明是float或double类型,其运算结果会自动保持精度。但要注意float或double类型数据原则上不允许做比较,正是因为截断误差的存在。通常用以下这种方式对比浮点数据:
float a = 25600001;
double b = 2.56e7;
if((a-b)<1e-10 || (a-b)>1e10)
{
cout<<"a == b"<<endl;
}
else
{
cout<<"a != b"<<endl;
}
上述程序的最终打印的是a == b,如果将a也定义位double,则会打印a != b.这就是有效长度带来的截断误差。因为这里float的有效长度位6位。
5、数据存储方式
C/C++编译器标准都遵照IEEE制定的浮点数表示法来进行float,double运算,无论是float还是double,在内存中的存储主要分成三部分,分别是:
(1)符号位(Sign): 0代表正数,1代表负数
(2)指数位(Exponent): 用于存储科学计数法中的指数部分,并且采用移位存储方式
(3)尾数位(Mantissa): 用于存储尾数部分
由图可知:
float型由于尾数部分位数是固定的小数点后23位,23位所能表示的最大数是2^23−1=8388607,所以十进制的尾数部分最大数值是8388607,也就是说尾数数值超过这个值之后,float将无法精确表示,所以float最多能表示小于8388607的小数点后7位,但绝对能保证的为6位,也即float的十进制的精度为为6~7位。
double数据类型的推算过程和上述同理,唯一的区别在于尾数由23位扩展到52位,阶码由8位增加到了11位,计算方法不变。所以double的阶码(移码表示)为0~2047,偏移量为1024,故指数范围为-1024~1023,得表示范围为(2^1023*2)~(-2^1023*2)即为-1.7E+308~1.7E+308,绝对值最小可以取到2^-1024,精度则为2^52-1=4503599627370495,为16位。所以精度最高位16位,一定可以保证15位。