@[TOC]
0. 浮点数关于有效范围一些问题
上一篇
上一篇大概地说了浮点数的精度问题和有效范围大小,还是有些东西没有说出来,我觉得还是应该说一说,我们常说的单精度有6 ~ 7位的有效范围,而双精度有15 ~ 16位的有效范围,这里所指的有效范围并不是该数值的大小,==这是很多初学者的一个误区==,并不是说这个单精度的float只能存储6 ~ 7位怎么大的数,如果是1234578这样的数则无法存储,这是错误的,想要理解这里的有效范围,还需要知道浮点数的存储方法,浮点数使用科学记数法来表示存储的,最大可以达到3.4E38,这是一个很大的数,达到了38位之多,显然不是上面所说的6 ~ 7位,这个有效范围可以认为是38位中的前6 ~ 7位,因为是使用科学记数法表示,而6 ~ 7 位又是根据尾数来得出来的,尾数又规定在1到2之间,也就是说最高位必须是1,而后面的数可以是000000(23个0),或者最大值为2,也就是1.1111111(23个1)==需要注意这里的尾数使用二进制表示的==,而2 ^23在6 ~ 7位之间,尾数可以保存6 ~ 7 位,然后后面38个0,这才是精度的根源。如果看不懂就去百度IEEE754,还是看不懂也没关系,初学者不需要了解怎么多,我只是普及一下。
1. C++如何确定常量的类型
C++如何确定常量的类型,老规矩,我们举个例子:
大家都知道在C++中有两种定义常量的方法,一种是使用#define的方式,还有一种就是下文要说的const。
#define MAX 123456789
const int Max 12345679
区别在于#define 不必定义该常量属于什么类型,是int,还是long int,而const定义的常量必须指明类型,至于哪种定义常量的方法好?我们推荐使用第二种,至于为什么,后面会说,我们现在主要来讨论C++如何确定常量的类型,假设我们就使用#define定义了 MAX = 123456789怎么一个常量,那么C++会如何确定常量类型呢?
#define MAX 12456789
std::cout <<sizeof(MAX) << std::endl;
来看运行结果:
结果是4,说明C++将MAX保存为int类型。
如果我们把这个数变一下:
#define MAX 36456465ll
std::cout <<sizeof(MAX) << std::endl;
运行结果:
我们将MAX 后面加了两个LL,还记得LL表示什么吗?对,表示的是long long类型。
下面的结论是需要记住的:在C++中将使用这几种类型中能够存储该数的最小类型来表示,前提是该数后面没有后缀,如果有后缀,则按后缀指定的类型来存储,至于浮点数呢,C++规定过只要不加f后缀的浮点数默认都为double,所以想要将浮点数存储为float,就需要特别的加上后缀f,这是和整形的不同。
以上说的都是对于十进制的存储方式,而对于八进制或者是十六进制,它们的存储方式为int,unsigned int,long,unsigned long,long long或者是unsigned long long。至于为什么会使用无符号的类型来存储,这是因为十六进制常用来表示内存地址,内存地址是没有符号的,因此unsigned int 比 long更适合来表示十六位的地址。
2. const除了修饰常量还能干什么
下面来说说const,const除了上面的用法,也就是定义常量,用const修饰变量时,一定要在初始化的时候进行赋值,否则之后是无法赋值的。
还有一些其他的用法,当然,如果你刚接触到上面的内容,这个可以跳过。
常量指针:
int number = 666;
const int * p = &a;
// int const * p 这种方法和上面等效,这个指针被修饰为常量指针,就是不可以通过这个指针修改变量的值。
number = 66; //但是可以通过number修改,也就是间接修改了指针指向的变量。
// 并且需要注意的一点是虽然不可以通过这个指针修改变量的值,但是可以修改指针所指向的变量,也就是说下面是合法的。
int number_2 = 1;
p = &number_2;
就好比我有一台电脑,装的是xp系统,有一天邻居小姐姐想跟我借电脑用一下,但是她觉得xp系统老掉牙了,想重装为win10系统,这时我就告诉她,不可以,重装只有我可以,这是我的电脑,她虽然不能给我的电脑重装系统,但是它可以选择跟其他人借用有win10系统的电脑。这就是常量指针,对应的还有一种指针常量,往下看。
指针常量:
int number = 666;
int * const p = &number;
// 千万不要写出 const * int p,这是错误的写法。
// 指针常量指向的地址不能改变,但是地址中保存的数值是可以改变的。
*p = 6; // 可以
int number2 = 6;
p = &number2; // 不可以
除了以上两种,还有一种结合了上面两种,叫做指向常量的长指针。
int number = 666;
const int * const p = &number;
// p既不能改变指向地址,也不能改变值,这个属于它们三个中的大哥。
还有就是如果给函数的返回值修饰了const,则接收返回值的变量类型也必须同样被const修饰。
3. 通用字符名
长话短说,如果要表示中文,显然一个字节是不够的,至少需要两个字节,而且还不能和ASCII编码冲突,所以,中国制定了GB2312编码,用来把中文编进去,类似的,日文和韩文等其他语言也有这个问题。为了统一所有文字的编码,Unicode应运而生。Unicode把所有语言都统一到一套编码里,这样就不会再有乱码问题了。。Unicode通常用两个字节表示一个字符,原有的英文编码从单字节变成双字节,只需要把高字节全部填为0就可以。想要深入了解请单击
通用字符名类似于转义字符,使用\u和\U打头,\u然后跟一个八进制,\U后面跟的是十六进制,可以这样用:
int k\u0025d;// 这样定义变量名
cout << "\u0025"; // 打印该字符
这样就可以在控制台打印出我们想要字符,比如各种图案。但是前提是要支持通用字符名,如果不支持,就会提示
一般黑框框是显示不了特殊字符的,给大家找到一个中文转unicode的网站:中文字符与Unicode字符相互转换
当使用\u6211打印出来的便是我:
4. char的符号问题
char的有无符号和int不太一样,它比较独特,char在默认情况下不像int那样,默认既不是unsigned char也不是signed char,是否有符号由C++决定,在我的编译器上可能是有符号类型的,你的终端可能是无符号类型,如果你不确定char,则应该尽可能的显式去声明是nusigned 还是signed,如果你只是存储ASCII字符,则无关char是什么类型,它都可以保存。
5. bool
ANSI/ISO C++标准添加了一种名叫bool的新类型,它只占一个字节,只保存true和false这个已经宏定义好的字面值,只有假和真两种表现方式,有些人一听到真假就想到01,一想到01就认为该类型的变量只能保存0或1,其实这种理解是不对的,该变量只保存true和false这两个值,并不是保存0和1,除了0被替换为false之外,所有的数字,1,5,8等等都会被替换为true,包括负数,同样反过来,将bool类型的变量赋值给int类型的变量,只会出现0和1这两个值。
bool b1 = true // 正确
bool b2 = 4; //正确,但4会被替换为1
int a = b2; // a的值为1,而不是4,也不是true
6. 运算符的优先级和结合性
简单来说先考虑优先级,再考虑结合性。
当两个运算符的优先级是一样的话,要使用结合性进行判断:
例如:
int a = 10*5/6;
//由于/ 和*的优先级是一样的,这时候就应该用结合性判断是从左往右算,还是从右往左算。