C++基础-基础数据类型



类型简介

C++的基础类型分为2个大类,整型和浮点型。整型和浮点型的内部又分为几种类型。之所以要这样做是因为C++认为没有一种类型可以满足所有的需求。为了更好的和系统匹配,甚至同一种类型在不同的系统实现中都不一样,目的就是更好的匹配系统,达到更快的速度。
本篇博文对每一种类型进行了分类介绍,也介绍了每一种类型对应的字面量的知识。

整型

C++的整型用来表示整数值,分为charshortintlonglong long一共5种。
其中char类型相对于其他4个更加特殊,可以单独分析。

整型类型宽度

C++的其他4种整型没有固定宽度,同一种类型在不同的计算机中可能有不同的宽度。
比如有的老式电脑的int类型宽度为16位,现在的个人PC的int类型宽度一般是32位。

C++只确保了每种类型的最小宽度。

类型 宽度
short 至少16位
int 至少和short一样长
long 至少32位,且至少和int一样长
long long 至少64位,且至少和long一样长

可以用C++内置的运算符sizeof查看当前计算机每种类型的宽度,单位为字节。

整型类型取值范围

整型类型的取值范围由类型的宽度和符号类型决定。
每一种整型类型都分为有符号类型无符号类型

有符号类型的正值和负值数量几乎相同,比如32位的int取值范围是:- 2 31 2^{31} 231 ~ - 2 31 2^{31} 231 - 1。
而无符号类型不包含负值,最小值为0,比如32位的unsigned int取值范围是:0 ~ 2 32 2^{32} 232 - 1。

如果赋值的整数超过了某个类型的取值范围就会产生溢出(上溢和下溢),溢出一般情况下的规律相当于里程表,如果超过了限制,其值会紧跟着范围另一边取值。

(下面内容了解即可)
可以通过C++的climits头文件查看不同整型类型的取值范围。
下面是使用climits查看除char类型以外类型的最大值的程序实例:

#include <iostream>
#include <climits>
int main()
{
    
    
	using namespace std;
	short n_short = SHRT_MAX;				// 赋值为short的最大值
	unsigned short n_un_short = USHRT_MAX;  // 赋值为unsigned short的最大值
	int n_int = INT_MAX;					// 赋值为int的最大值
	unsigned n_un_int = UINT_MAX;			// 赋值为unsigned int的最大值
	long n_long = LONG_MAX;					// 赋值为long的最大值
	unsigned long n_un_long = ULONG_MAX;    // 赋值为unsigned long的最大值
	long long n_llong = LLONG_MAX;			// 赋值为long long的最大值
	unsigned long long n_un_llong = ULLONG_MAX;        // 赋值为unsigned long long的最大值

	cout << "Maximum values:" << endl;
	cout << "short: " << n_short << endl;
	cout << "unsigned short: " << n_un_short << endl;
	cout << "int: " << n_int << endl;
	cout << "unsigned int: " << n_un_int << endl;
	cout << "long: " << n_long << endl;
	cout << "unsigned long: " << n_un_long << endl;
	cout << "long long: " << n_llong << endl;
	cout << "unsigned long long: " << n_un_llong << endl;
	return 0;
}

我的电脑输出的结果为:
在这里插入图片描述

如何选择适合的整型

一般情况都是使用int,int类型被设置为对目标计算机最自然的长度。
如果已知变量可能表示的整数值大于16位整数的最大值(有符号的是32767,无符号的是65535),则最好用long类型。即使已知当前计算机的int是32位,这是为了保证可移植性。
如果要存储的值超过20亿,不可能为负的变量可能最大值超过40亿,则使用long long和unsigned long long。
如果是大型整型数组,数组的元素可能最大值short类型足够满足,最好使用short,可以节省内存空间。
如果变量表示的值不可能为负,就可以使用对应的unsigned类型。

整型字面量

字面量就是含义和字面意思一致的量。比如100,含义就是数字100。
字面量要和符号常量做区分,符号常量是指值不变的特殊变量,比如const int a = 10; 意思是a的值永远都是10不会改变,但是a可不是字面量,因为a的值是10,而不是字面的字符a。

整型字面量的表示形式

基于4种常见的进制,整型字面量有4种表示形式:
1.二进制形式:0b或者0B开头,比如0b0100 = 十进制的4
2.八进制形式:0开头,比如017 = 十进制的15
3.十进制形式:和日常的整数含义一直,比如100就是指十进制下的100
4.十六进制形式:0x或者0X开头,比如0x1F = 十进制的31

注意,表示形式和实际在内存中的存储方式是两回事!
表示形式是给程序员看的,是为了表达的方便,比如用16进制表示地址的值会比十进制更直观。
但是,任何表示形式的数据,存储到计算机的内存中,都是以二进制的格式存储的

如何确定整型字面量的类型(本节了解即可)

整型字面量和整型变量不同,它并没有显式的规定其类型,但是它有一套内在的规则。

对于大部分情况,整型字面量都是int类型。

具体的规则分为2种,后缀和长度:
1.如果加上了后缀,字面量的类型就可以直接确定。有L(l)和U(u)三种后缀,L(l)表示long类型,LL(ll)表示long long类型,U(u)表示unsigned。
比如LU或者UL就表示unsigned long类型,ULL(LLU)表示unsigned long long 类型,以此类推。
2.如果没有后缀就看长度,对于长度,十进制表示的字面量和其他进制表示的字面量规则有所不同。对于不带后缀的十进制整数,以int,long,long long三种类型中能够存储该字面量的最小类型来表示。对于不带后缀的其他进制整数,以int, unsigned int, long, unsigned long, long long ,unsigned long long这六种类型中能够存储该字面量的最小类型来表示。之所以这么做是因为,对于二进制,八进制和十六进制表示的字面量,它们经常用于表示地址这类无符号的数据。

实际上这些规则应用得很少,因为C++有自动类型转换的机制,会将赋值号右边的值转变为左边变量的类型后,再为其赋值。
比如:unsigned int n = 4000000000L; 这行代码
字面量是40亿,L后缀表示为long类型的字面量,但是赋值给unsigned int类型的变量n,那么这个字面量会被自动转换为40亿的unsigned int类型后再赋值给n。
再比如: short n2 = 2000; 按照上面的规则,2000的字面量看长度应该是int类型,但是赋值给short类型的n2后,会自动进行类型转换,变成2000的short类型。

所以,可以看出,确定字面量类型的规则在实际的赋值中其实经常不起作用,因为还有自动类型转换。

char类型

char类型用来表示字符,它相对其他整型类型更加特殊。
char类型通过编码的方式来实现字符的表示。也就是在每个字符和对应的二进制数之间建立1对1的映射。最常见的编码就是ASCII码,除此之外,Unicode编码也经常遇到。
编码的概念在使用char类型时其实不太容易感觉得到,虽然每个字符在内存中都是存储为二进制整数,但是通过对应的输出工具输出后,比如cout,看到的还是字符而不是二进制的编码值。这其实是因为输出工具自身会做相应的转换。

char类型的宽度为1个字节。
(下面内容了解即可)
但这里有很少用但是比较麻烦的地方,C++的1个字节不一定是8位。C++的1个字节必须等于或者刚好超过实现系统的基本字符集。也就是说C++的1个字节足够表示实现该系统的基本字符。所以,有的特别的系统可能一个字节为16位,大部分系统1个字节是8位。

char类型的符号

char类型是有符号还是无符号类型由C++的编译器的实现决定。
但是可以通过加前缀signed和unsigned确定符号类型,signed char就是有符号类型,unsigned char就是无符号类型。

字符字面量

字符字面量一般是用单引号括起来的单个字符,比如’A’,'b’等。
值得注意的是,'5’是字符的5,它对应的ASCII码是53,也就是说字符5存储到计算机内部是1字节的二进制数53。

但是,对于没办法从键盘上输入的字符字面量,单引号的表示法就失效了。
C++提供了转义字符的概念,转义字符就是用特殊的字符组合来表示键盘上没有的字符。
比如’\n’,'\a’等等。
需要记住的转义字符请看下面的表格:

字符名称 C++代码
换行符 \n
水平制表符 \t
反斜杠 \\
单引号 \’
双引号 \"

(下面内容了解即可)
除了这些转义字符外,C++提供了更加通用的"通用字符名",它一共有4位或者8位,对应Unicode的码点,格式为:‘\uxxxx’或者’\Uxxxxxxxx’。大U后有8位十六进制数,小u后有4位十六进制数。\u或者\U表示这和Unicode的码点对应,xxxx或者xxxxxxxx是码点具体的值。比如’\u4E00’对应于汉字的“一”。这些’\uxxxx’格式的通用字符名对应的字符就是Unicode编码在该数字下对应的字符。
但通用字符名和C++当前系统的内部编码实现方式无关,通用字符名是和系统无关的,是C++规定的一种可以表示任意字符集的方式。因为Unicode非常大,可以涵盖世界上已知的所有字符。比如’\u4E00’对应的是汉字“一”,但是,汉字“一”在每个系统内部如何编码存储要看系统本身。但内部如何存储在这里对程序员来说不重要,程序员只需要知道汉字一的Unicode编码,就可以在需要的时候得到字符:汉字一。
你可以把’\uxxxx’想象成一种特殊的转义字符,它用\u的前缀接4个16进制数字来表示任何在Unicode字符集出现的字符,但是它在每个系统内部如何存储我们不需要了解。
这部分知识也是基本不用,了解即可。

bool类型

严格来说,布尔类型也算是整型,不过它比char类型还要特殊。
它是一种表示逻辑真假的类型,类型名为bool。
布尔类型的变量取值只有truefalse,true代表真,false代表假。

布尔类型为什么算特殊整型呢?
是因为C++把值为非0的值都认为是true,把值为零(比如整数0,浮点数0.0,NULL)都认为是false。

在给布尔变量赋值或者用于if的条件判断时,非零值和true是完全等价的,值为零和false是完全等价的。
比如代码bool a = NULL; 完全等价于 bool a = false;
比如if (true) 和 if (-100)是完全等价的,因为-100是非零值。



浮点类型

浮点类型用来表示带小数点的数字,C++的浮点类型有三种float,double和long double。

浮点数内部存储方式简介

浮点数的内部存储比整数要复杂一些。
简单说,分为2部分:第一部分存储基准值,第二部分存储缩放因子。
比如3.1415,基准值就是0.31415的二进制形式,缩放因子也是2进制的幂。

浮点类型的精度和指数范围

每种浮点类型的区别在于数值的精度和指数的范围。
精度表示数字的有效位数,C++规定了每种类型的最小精度。
float类型是至少前32位有效,这里的有效是二进制形式,前面已经说过了,浮点数存储在计算机内部,
不管是第一部分还是第二部分都是用二进制存储,比如有的实现的float在内部存储是符号位1位,指数8位,小数位23位,加起来一共32位有效位。有时候需要计算的数字的指数特别大或者小数点后的数字特别长,导致32位不够完全存储,这时候就会产生精度不够的问题。至少32位的有效位数指的就是只能用这32位尽力存储,不够的部分就会省略掉。
同理,double至少是48位而且不小于float的有效位数。
long double至少不小于double的有效位数。
通常情况,float的有效位数是32位,double为64位,而long double是80,96或者128位。
精度指的是整个浮点数的有效位数,而我们还比较关心浮点数的指数范围。
这决定了浮点数能表示的数值能多大或者多小。
指数范围会受到存储指数的提供的内存空间限制。
比如32位的float类型一般提供了8位存储指数,也就是之前提到的缩放因子,这里的8位存储的幂是2进制的幂。
换算成对应的10进制的幂是-37~38。也就是浮点数对应10进制的幂,最多是a x 1 0 38 10^{38} 1038,a就是第一部分的基准值。比如0.314 x 1 0 38 10^{38} 1038

每个编译器的具体实现可能都不同,如果想查看自己系统的浮点数的精度和指数范围,可以看cfloat这个头文件。

浮点数因为精度在计算中产生的问题

当精度不够时,浮点数的算术运算结果可能完全不准确,特别是在处理一些很大或者很小的值,就容易出现这样的问题。

#include <iostream>
int main()
{
    
    
	using namespace std;
	float f1 = 3.14E23F;			//这是一个很大的浮点数
	float f2 = 3.14E23F + 1.0F;		//将f1加上1后存储到f2
	cout << f2 - f1 << endl;		//预计结果是1.0,可实际结果确实0
	return 0;
}

这个程序的运行结果预计是1.0,但是实际结果却是0。
这就是因为3.14E23这个数字非常大,小数点左边有24位数字(314上21个0),这个数字加1实际上加到小数点左边第24位,但是float类型对应的十进制数字一般只有前6位有效,所以对第24位的改变计算机根本没有存储。所以加1这个步骤并没有被记录下来,所以f2-f1的值才为零。

浮点字面量

浮点字面量和整型字面量类似,就是和字面意思一样的小数。

浮点字面量的类型

浮点字面量的类型一般都默认为double类型,如果想设置为float或者long double类型就需要加后缀。float的后缀是f或者F,比如3.14F。long double的后缀是L或者l,比如3.14L。
这相比整型确定类型的方式要简单很多,而且这个知识点确实也会使用,比如把浮点字面量赋值给float类型的变量时,由于字面量默认是double类型,进场会弹出"赋值会产生截断"的警告。这时候在字面量后面加上F的后缀就可以取消这种警告。

浮点数的表示法

有2种表示法:
1.标准小数点的表示法
和我们数学的习惯一致,比如3.14,8.0等
2.E表示法
E表示法很像数学中的科学计数法
E的右边是10的幂次,如果幂为正数,+可以省略。
E的左边是一串数字,根据E右边的数字乘以相应的10的幂,得到的结果就是最终的浮点值。

猜你喜欢

转载自blog.csdn.net/qq_983030560/article/details/128942400