C++查缺补漏之变量和基本类型

基本内置类型

1.块处理存储
一般来说计算机以位序列存储数据,每一位存储0或1,一段内存可能存储着0001010010101010...但是这样的存储是没有任何意义的,让存储器具有结构的方法是块处理存储,那么什么是快处理存储呢,就是用2^n表示一个存储块的位数(一般以8位作为一个块),这样操作起来更加方便。
如下图:
123456 01110001
123457 10101001
123458 10100100
要操作一个块,需要什么东西呢?那就是所谓的地址,上面的123456就是这个块的地址,也相当于它的标示符,但是要让地址为123456的这个字节具有意义,那么还需要存储在该地址的值的类型,一旦知道了该地址的类型,那么就知道表示该类型需要多少位和如何解释这些位。
比如123456这个块如果是整形类型的(当然int需要占用四个字节)那么表示的就是112,如果表示的是ISO-Latin-1的一个字符,那么就表示小写字母q
下面来看一个例子:
#include <iostream>
#include <iomanip>
#include <stdio.h>
using namespace std;

int main(int argc, char const *argv[])
{
	unsigned int number = 16843009;//二进制为<span style="font-family: 'Comic Sans MS';">00000001</span><span style="font-family: 'Comic Sans MS';">00000001</span><span style="font-family: 'Comic Sans MS';">00000001</span><span style="font-family: 'Comic Sans MS';">00000001</span><span style="font-family: 'Comic Sans MS';">
</span>	unsigned int * pNumber = &number;
	cout<<reinterpret_cast<int>(pNumber)<<endl;//打印指针地址
	cout<<*pNumber<<endl;//unsigned类型时的值
	unsigned char * ptrChar = reinterpret_cast<unsigned char *>(pNumber);//unsigned int * 转为 unsigned char *
	cout<<static_cast<int>(*ptrChar)<<endl;//unsigned char类型以int类型输出
	ptrChar++;
	cout<<static_cast<int>(*ptrChar)<<endl;
	ptrChar++;
	cout<<static_cast<int>(*ptrChar)<<endl;
	ptrChar++;
	cout<<static_cast<int>(*ptrChar)<<endl;
	while(1);
	return 0;
}
最后输出结果为:
技术分享
观察之前我们的那个整形number,不正是由四块值为00000001组成的么,只是解释为unsigned int 类型时为16843009,解释为unsigned char 类型时为1.

2.除了bool类型的整形才可以是unsigned 或者是signed ,如果在只写unsigned 不加上具体类型,那么就是unsigned int类型的 。

3.特殊的char类型
与其他整形不同,char类型有三种不同的类型:char , unsigned char , signed char。但是只有两种表示形式unsigned char 或者signed char。这句话是什么意思呢?我们知道(int,short,long)类型默认都是signed类型的,但是char类型时没有默认类型的,具体是signed还是unsigned类型,还要由编译器而定。要想确定编译器默认是signed还是unsigned,可以
char ch =-1;
printf("%d\n",ch);
如果打印的是-1,那么表明是signed类型的
若是255,那么表明是unsigned类型的
我在gcc上面测试以后发现是signed类型的,所以在编写char类型的时候最好还是加上signed或者unsigned吧,不然又会多了一些莫名奇妙的错误。

4.浮点型
都知道float表示的浮点型使用一个字来表示,且精度是单精度,只有6位有效数字
double类型占用两个字节,精度为双精度,至少保证了10位的精度
这里的精度到底是什么意思呢?我们来看一下float和double内部到底是如何存储的:

类型float大小为4字节,即32位,内存中的存储方式如下:


 符号位(1 bit)

指数(8 bit)

尾数(23 bit)


类型double大小为8字节,即64位,内存布局如下:


符号位(1bit)

指数(11 bit)

尾数(52 bit)

对于float类型来书8位的指数取值范围为:-2^7~2^7+1(-127~128)
double类型11位指数取值范围为-2^10~2^10+1(-1024~1025)
指数的含义是什么呢?
  • 负指数代表着浮点数能表示的绝对值最小的数
  • 正指数表示了浮点数能表示绝对值最大的数
float的范围为-2^128 ~ +2^128,也即-3.40E+38 ~ +3.40E+38;double的范围为-2^1024 ~ +2^1024,也即-1.79E+308 ~ +1.79E+308

接着我们来看一下尾数:
  • float类型的尾数为2^23(8388608),长度为7为,但是又不满七位
  • double类型尾数为2^52(4503599627370496),长度为16,但是又不满16
所以所谓的精度就是这里的尾数所能表示的数的长度
下面我们来看一个例子:
#include <iostream>
#include <iomanip>
#include <stdio.h>
using namespace std;

int main(int argc, char const *argv[])
{
	float f1 = 1.123456789123456789;
	double d1 = 1.123456789123456789;
	cout<<setprecision(20)<<"float:"<<f1<<endl;
	cout<<setprecision(20)<<"double:"<<d1<<endl;
	while(1);
	return 0;
}
可得到输出结果为:
技术分享
我们可以明显的看到float从第7位(为什么不是第六位呢?因为8388608)有效数字开始就开始不准确了
double类型也就只显示了前16位,后面的都被截断了。所以以后再具体应用中需要辨别他们之间的区别,float的精度损失是不可忽视的,使用double类型基本上是不会出错的,双精度的计算代价相对于单精度乐意忽略,在某些机器上double类型比float类型要快得多(可能是硬件上做了优化了吧)。但是long double一般来说是没有必要的。。。
最后说一点,上面我们看到了浮点类型的结构,里面有一位固定符号位,所以浮点类型是没有unsigned的!!!

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。