第二讲
聊聊c/c++中常见类型:
按理说bool一个bit就能搞定,但是并非如此。
一个二进制位为1bit,表示01
ascii码中, 'A' = 65,即64 + 1,01000001
下面是一个short类型,8个bit代表1byte
机器数中,符号位0+,1-,表示-7时,最简单的就是下面这种了
问题来了
当有个上面这样的数据时,两者相加,结果是多少呢?肯定不是10000000 00001110,-14了。
学过计算机组成原理的都知道,计算机中的加法是补码加法,正数,原码 = 补码 = 反码, 对于负数,反码就是除符号位各位取反,补码 = 反码 + 1。
这样 -7 + 7 = 0,而不是-14了 。
下面这段代码:
char ch = 'A';
short s = ch;
cout << s << endl;
打印出来是65,这里是把'A'代表的数字传给了s。
char类型是1byte,即8bit,存储A时并不是直接把A存在内存,而是存储代表A的ascii编码值,'A' = 65,即存储了65的二进制值。
所以65存在short类型的低位中,高位置为0,就有了65。
short s = 67;
char ch = s;
cout << ch << endl;
这段代码打印结果就是 C 了,char类型默认装载低位数值,然后打印它对应的字符
int i = pow(2, 23) + pow(2, 21) + pow(2, 14) + 7;
short s = i;
cout << s << endl;
int是4byte,short是2byte,那么可以推出short只能保存2^14 + 7这个值了,打印结果如下:
再看下面这段代码:
short s = -1;
int i = s;
cout << i << endl;
这里,对于short s = -1,并不是填充0了,计算机会填充符号位到空余的比特中,所谓“符号扩展”。
运行结果如下,并不是一个2^16 - 1是不是。
float类型
牺牲一些比特来存储2^-1, 2^-2....这种,不断逼近0.1415值
1-8-23,1-15-48,国际标准中float和double的 符号位s-指数位exp-小数位xxx。
计算公式如下:
(-1)^s * 1.xxxxx... * 2 ^ (exp - 127)
比如说float的7,怎么表示呢:
7 * 2^0 = 3.5 * 2^1 = 1.75 * 2^2,无论如何都可以把一个数化为1到2之间的小数,这样子就能表示了
1.75 * 2^2,s = 0,exp = 129,xxx = 0.75。
看下面的代码:
int i = 5;
float f = i;
cout << f << endl;
这里怎么在内存赋值呢,此5非彼5,根据上面的存储方式,float的5要看成1.25 * 2^2。
这才是float下的5存储方式:
地址
int i = 37;
float f = *(float*)&i;
cout << f << endl;
&i是取其地址,类型是int*,我们强制转换为float*型,都是4byte,但是注意其间地址指向的内存中数字并未发生转换,仍然是int 37 的存储方式,再使用*取其值,现在值为float类型了,但是并未做上面的那种转换。
那么这个f,就会是一个非常小的值,因为37中的数字基本都在小数xxx位,2^-23和2^-20,而指数位是2^-127。
float f = 7.0;
short s = *(short*)&f;
cout << s << endl;
同上,指针解引时候,2byte的s会映射f的高16位,因此不是0。
但是我运行是0:
这里我尝试将f增大,s会成为负数,我的思考是f的低16位存储为short,并非老师说的高16位
或者说,老师说的是在大端机器的结果,而我的电脑是小端机器
我尝试缩小f,得到正数,增大f时得到负数:
float f = 0.000000000000000000000021000210002100021;
short s = *(short*)&f;
cout << s << endl;
6656
[Finished in 0.482s]
float f = 8888.0;
short s = *(short*)&f;
cout << s << endl;
-8192
[Finished in 0.468s]