萌新不看会后悔的 C++ 基本类型总结(一)
其他文章:
c++的基本类型包括 char,short,int,long,lang lang(C++新增的),double,float,bool,其中除了 double,folat 两种浮点数类型之外都有有符号和无符号两种类型,也就是说一共 12 种基本类型,至于为什么浮点数没有无符号类型,后面会说。
0.浮点数
浮点数包括 float,和 double,还有 long double,这些书上面都有解释,我们不再赘述,只挑重点讲一讲:
单精度 float 和双精度 double 浮点数,那么单精度和双精度有什么区别?
就是前者占 4 字节,后者占 8 字节,前者有效数字位数位 8 位,后者为 16 位,还有就是取值范围不同。
等等,这显然不是我们想要的答案,比如说我给你举个例子:
运行结果:
通过这个你能告诉我你就理解单精度和双精度了吗?我相信很多人还是只知道有单精度和双精度这个叫法,却不知道具体意义。
想要知道具体,我们需要查阅 IEEE754 标准,该标准定义了 float 和 double,float 有 32 位,double 有 64 位,不管是 32 位还是 64 位,它们都由符号位,指数位,和尾数位构成:
| 种类 |符号位 | 指数位 |尾数位 |
|--|--|--|--|
| float | 第 31 位(占 1bit) | 第 30~23 位(占 8bit)| 第 20~0 位(占 23bit) |
| double| 第 63 位(占 1bit) |第 62~52 位(占 11bit) | 第 51~0 位(占 52bit) |
取值范围看指数部分,float 指数部分占 8 位,也就是 0 ~ 255,由于有正负,所以为-128 ~ 127, 标准规定 float 偏移量为 127,也就是-1-127~255-127 为-128 到 128。
取值范围有-2 ^128 到 2 ^128,是不是够大?也就是约等于你们熟悉的-3.4E38 到+3.4E38。
精度范围看尾数部分,23 位所能表示最大的数是 2 ^23-1=8388607,也就是说尾数值超过这个值后 float 将无法精确表示,所以 float 最多能表示小于 8388607 的小数点后 8 位,但绝对能保证为 7 位,这也是 float 精度位 7 ~ 8 位的原因。
同理,double 类型的指数位为 11 位,取值范围有-2 ^10232 到 2 ^10232,既为你们熟悉的-1.7E+308~1.7E+308。
精度范围为 2^52-1=4503599627370495,为 16 位。所以精度最高位 16 位,一定可以保证 15 位,这也 double 精度位 15 ~ 16 位的原因。
也是单精度 8 和双精度 16 的由来。
1.各种类型占用内存大小问题
下面先来看一段代码。
与所有人一样,一上来我们先了解各个类型占据内存的大小。
>这里有一个误区:在不同的编译器,每个类型占用的内存可能是不同的,这和编译器有关,一个类型占用多少字节由编译器在编译期间决定,并不和系统是否是32位和64位有关,不要以为在16位机器上就是16位,在36位机器上就是32位。
可以查看<limits.h> 头文件,int 和其他类型的大小是由<limits.h> 中的宏定义来决定的:
所以我这里就不再列出烂大街的最大值,最小值。
我只是告诉你,这个值应该怎么得到。要知其然,还要知其所以然。
比如我们知道 char 的字节为 1,一字节 8 位可以有 256 种组合,所以 int 的字节为 4 也就是 256*256 等于 65536,这种东西我们理解就好了,没必要背这个最大值,最小值,只需要如何得到就好了。
2.sizeof 和 strlen 的区别
>然后说一下sizeof和strlen的区别,可能有很多萌新记不住这两个的区别:
>
>>sizeof() 是运算符,它不是函数,不要因为它长的像函数,就上它的当,sizeof 其值在编译时就已经计算好了,参数可以是数>组,指针,对象,函数等等,它的功能就是获取数组,指针等类型的字节大小。
>数组——编译时分配的数组空间大小
>指针——存储该指针所用的空间大小
>类型——该类型所占空间大小
>对象——对象的实际所占空间大小
>函数——函数的返回类型所占的空间大小,这里的返回类型自然也不能 void
>
>>strlen()是函数,要运行时才能计算,参数必须字符型指针(char*),函数原型为:
Checkreturn sizet __cdecl strlen(_Inz const char * _Str);
该函数的功能是返回字符串的长度,该字符串可能是自己定义的,也可能是内存中随机存储的,该函数实际完成的功能是从代>表该字符串的第一个地址开始遍历,知道遇到结束符 NULL,返回的长度不包括 NULL。
3.整形字面值
与 C 相同,C++也有三种不同的书写方式来书写整数。
1.使用前一位或者两位来标识数字常量的基数,如果第一位是 1 ~ 9 则表示基数为 10,也是十进制写法。
2.如果第一位是 0,第二位是 1 ~ 7,则基数为 8,也就是八进制。
3.如果前两位为 0x 或者 0X 则表示基数为 16,相当于十六进制。
运行结果:
为什么要有这几种书写方式呢,在有些地方是使用八进制或者是十六进制表示,我们可以直接使用该表示方法赋值给 number,而不必转换为十进制,总而言之,就是为了方便,为了偷懒,反过来,输入识别进制是有了,反过来,C++也提供了不同进制的输出方式,但 C++默认是十进制的输出方式,想要改变默认的十进制输出方式,需要用到 cout 的一些特殊特性,头文件 iostream 提供了 dec,hex,oct,分别用于表示十进制,十六进制和八进制:
运行结果:
>需要注意的是在修改之前,之前修改的格式会一直生效。
4.有无符号类型之间运算情况
说完 sizeof 和 strlen,继续说基本类型的长度,计算机内存的基本单位是位(bit),8 位为一个字节,每一位有 0 和 1 两种组合,也就是说一个字节有 ==*2 2 * 2 * 2 2 2 * 2 * 2 2 = 256*== 种组合。上面使用 sizeof 得到 char 的字节为 2 字节,也就是说,char 类型可以表示 0~ 255 或者 -128 ~ 127 ,上面说过,除了浮点数没有有无符合之分,剩下的类型都有有符合和无符号之分,也就是 char 支持 0~255,也可以支持-128 ~ 127,至于我们需要有符合还是无符号的,决定于我们的应用场景。
>执行运算时,如果一个运算数是有符号的,而另一个是无符号的,那么C/C++会隐式的将有符号参数强制转换为无符号类型,并假设这两个数都是非负数。
>当两种类型进行混合运算时,运算结果为正数时,结果不会出现异常,当运算结果为负数时就会出现异常结果,而且异常的结果往往很大。
运行结果:
5.有无符号类型之间的转换
下面再往深走一点,我们来说说有符合数和无符号数类型之间的转换,也就是二进制 01 之间的转换,说之前,我们需要先复习一下原码,反码和补码:
<font color=#6699ff size=3 face="STCAIYUN">原码:</font>
原码就是在最高位符号位用于表示符号,其他位表示值,比如 8 位一字节:
>正 1 的原码为 00000001
>负 1 的原码为 10000001
<font color=#cc0000 size=3 face="STCAIYUN">反码:</font>
反码的表示方法为正数的反码时其本身,而负数的反码是在其原码的基础上,符号位不变,其余各数取反:
>正 1 的反码为 00000001
>负 1 的反码为 11111110
<font color=#009933 size=3 face="STCAIYUN">补码:</font>
补码的表示方法为正数的补码就是其本身,而负数的补码就是在其原码的基础上,符号位不变,其余各位取反,最后+1,也就是在反码的基础上+1:
>正 1 的补码 000000001
>负 1 的补码 111111111
复习了原码反码补码后,我们说:
1.无符号数,不存在正负之分,所有位都用来表示数的本身。
2.有符号数,最高为用来表示数的正负,最高位为 1 则表示负数,为 0 则表示为正数。
无符号数想要转换为有符号数需要三步:
1.看无符号数的最高为是否为 1。
2.如果不为 1,则有符号数就直接等于无符号数。
3.如果无符号数的最高位为 1,则将无符号数取补码,得到的数就是有符号数。
举个例子:
>无符号数 10 转换为有符号数
无符号数 10 的二进制写法:0000 1010
根据三步法得到:
有符号数 10 的二进制写法:0000 1010
还是 10
>无符号数 129 转换为有符号数
无符号数 129 的二进制写法:1000 0001
根据三步法得到:
反码:1111 1110
补码:1111 1111
也就是说转换成有符号后,代表的是-127
同样,有符号数想要转换为无符号数,同样需要这三步:
1.看有符号数的最高位是否为 1,
2.如果不为 1(为 0),则无符号数就直接等于有符号数;
3.如果有符号数的最高位为 1,则将有符号数取补码,得到的数就是无符号数。
举个例子:
>有符号数-7 转换为无符号数
有符号数-7 的二进制写法:1000 0111
根据三步法得:
反码:1111 1000
补码:1111 1001
也就是无符号数 249
总而言之就是看符号位,如果是 1,就把它当作负数来处理反码,补码。
6.为什么会出现结果数值异常大
还记得上面有一句话是这样说的==当运算结果为负数时就会出现异常结果,而且异常的结果往往很大==。现在,我们来处理这个问题:
我们可以把变量的取值范围当作是汽车的里程表,一来为了好理解,而来确实是这样的,拿 char 来说:
这也就解释了为什么 unsigned int usa1 = 10 和 int sa1 = -100 相加会得到那么大的一个数,也就是常说的最大值加 1 变为 0 的故事。
7.为什么浮点数没有分有无符号类型
有无符号类型说完,我们来说说文章开头留下的问题,为什么浮点数没有有无符号之分:
想要使用 unsigned,就意味着最高为要用来表示数据,而不是正负,而浮点数定义中规定内存中的数据的第一位必须是符号位,因此两者是矛盾的,至于在哪看定义,请点击下面链接自行查看:
还有就是在某些编译器下,会将定义的 unsigned folat 和 unsigned double 自动转换为 unsigned int 类型,而不报错,这时使用 sizeof 来测量的话得出来的是 int 的大小,也就是 4.
,
版权声明: 本文为 InfoQ 作者【花狗Fdog】的原创文章。
原文链接:【http://xie.infoq.cn/article/3ca29005b1c75fa2cec39d05d】。未经作者许可,禁止转载。
评论