1、数据类型
整形家族:char short int long(有无符号)
浮点型家族:float double
构造类型:数组类型、结构体类型struct、枚举类型enum、联合类型union
指针类型:int *pi,char *pc,float *pf,void *pv
空类型:void表示空类型(无类型),通常用于函数返回类型、函数的参数、指针类型
2、整形在内存中的存储
2.1 原码、反码、补码
最高位为符号位,0表示“正”,1表示“负”。正数原反补相同
负数求补码,二进制表示原码,符号位不变,其他位取反为反码,+1为补码
2.2 大小端介绍
大端(存储)模式,是指数据的低位保存在内存的高地址中,而数据的高位,保存在内存的低地址中;
小端则低存低,高存高。(低位字节序,高位字节序)
为什么有大端和小端:这是因为在计算机系统中,我们是以字节为单位的,每个地址单元都对应着一个字节,一个字节为8bit,但是在C语言中除了8bit的char之外,还有16bit的short型,32bit的long型(要看具体的编译器),另外,对于位数大于8位的处理器,例如16位或者32位的处理器,由于寄存器宽度大于一个字节,那么必然存在着一个如何将多个字节安排的问题,因此就导致了大端存储模式和小端存储模式
内存中存的都是补码:
Signed char:正数:0000 0000->0(对应十进制的0)
0000 0001->1
0000 0010->2
0000 0011->3
……
0111 1111->127
负数:1000 0000->-128(直接转换)
1000 0001->-127
1000 0010->-126
……
1111 1110->-2
1111 1111->-1(八个全1是-1在内存中存的补码,取反+1
转换为原码是1000 0001)
unsigned char:0000 0000->0
0000 0001->1
0000 0010->2
0000 0011->3
……
0111 1111->127
1000 0000->128
1000 0001->129
……
1111 1110->254
1111 1111->255
signed short:0000 0000 0000 0000->0
0000 0000 0000 0001->1
……
0111 1111 1111 1111->32767
1000 0000 0000 0000->-32768
1000 0000 0000 0001->-32767
……
1111 1111 1111 1110->-2
1111 1111 1111 1111->-1
unsigned short:0000 0000 0000 0000->0
0000 0000 0000 0001->1
0111 1111 1111 1111->32767
1000 0000 0000 0000->32768
1000 0000 0000 0001->32769
……
1111 1111 1111 1110->65534
1111 1111 1111 1111->65535
总结:signed char取值为-128~127
unsigned char取值为0~255
signed short取值为-32768~32767
unsigned short取值为0~65535
例1:char a = -1
signed char b = -1
unsigned char c = -1
printf("a=%d,b=%d,c=%d",a,b,c)
输出结果是什么?
答:a=-1,b=-1,c=255
解释:有符号char取值-128~127,所以a,b赋值为-1
-1的原反补码:
原码:1000···0000 0000 0000 0000 0000 0000 0001(共32位)
反码:1111···1111 1111 1111 1111 1111 1111 1110
补码:1111···1111 1111 1111 1111 1111 1111 1111
因为a被赋值为-1,-1是32位的,而内存中存的是补码,把原转补后仍为32位,char a仍放不下,故截断,最后存到a中的是8个1,而%d 打印的是有符号的整型,故整型提升,提升补码,因高位为1,全补1,再取反+1到原码,最后打印原码。
对于无符号的c,因c本身为无符号的数,所以高位补0,而最后打印有符号整型,而正数的原反补码相同,则c打印出来为255
总结:整型提升看它自身原本类型
有符号:负数高位补1
正数高位补0
无符号:高位补0
例2:char a = -128
printf("%u",a)
printf("%d",a)
打印结果是什么?
答:结果为4294967168 -128
解释:-128原码:1000 0000 0000 0000 0000 0000 1000 0000
反码:1111 1111 1111 1111 1111 1111 0111 1111
补码:1111 1111 1111 1111 1111 1111 1000 0000
截断后仅保留后八位1000 0000
若以%u打印就是无符号整型,而正数的原反补码相同,则打印为一个很大的正数,若以%d打印需转原码
(原码转补码要取反+1,补码转原码也可以取反+1)
打印之前先进行整型提升,且a是有符号类型,赋给a的值是个负数,所以高位补1
补码:1111 1111 1111 1111 1111 1111 1000 0000->4294967168
反码:1000 0000 0000 0000 0000 0000 0111 1111
原码:1000 0000 0000 0000 0000 0000 1000 0000->-128
3、浮点数存储规则
根据国际标准IEEE(电气和电子工程师协会)754,任意一个二进制浮点数V可以表示成以下形式:(-1)^S * M * 2^E
(-1)^S表示符号位,即-1的S次幂,当S=0,V为正数;当S=1,V为负数
M表示有效数字,大于等于1,小于2
2^E表示指数位,2的E次幂
例:V=5.0(十进制)→ 101.0(二进制)→ 1.01 * 2^2(底数是2的原因为:在十进制中每一位是10的几次幂,在二进制中每一位就是2的几次幂)
= (-1)^0 * 1.01 * 2^2
S=0 M=1.01 E=2
但对于V=9.6→ 1001.100……(十进制转二进制,点前点后分别写成二进制)
点前第一位的权重是2的0次方,点后第一位是2的-1次方(就是0.5),但无论后边凑多少位,总是无法凑到0.6,此时就会出现精度丢失
对于float浮点数IEEE 754规定:
对于32位的浮点数,最高的1位是符号位S,接着的8位是指数E,剩下23位为有效数字M

对于64位的浮点数,最高的1位是符号位S,接11位E,剩52位M

3.1 IEEE 754对有效数字M和指数E,还有一些特别规定:
前面说过,1<=M<2,也就是说,M可以写成1.XXXXXX的形式,其中XXXXXX表示小数部分
IEEE 754规定,在计算机内部保存M时,默认这个数的第一位总是1,因此可以被舍去,只保存后面的XXXXXX部分,比如保存1.01时候,只保存01,等到读取的时候,再把第一位的1加上去,这样做的目的,是节省1位有效数字,以32位浮点数为例,留给M只有23位
将第一位的1舍去以后,等于可以保存24位有效数字
3.2 至于指数E,情况就比较复杂:
首先,E为一个无符号整数(unsigned int)
这意味着,如果E为8位,它的取值范围为0~255,如果E为11位,它的取值为0~2047,但是,我们知道,科学计数法中的E是可以出现负数的,所以IEEE 754规定,存入内存时E的真实值必须再加上一个中间数,对于8位的E,这个中间数是127;对于11位的E,这个中间数是1023,比如,2^10的E是10,所以保存成32位浮点数时,必须保存成10 + 127 = 137,即10001001。
3.3 然后,指数E从内存中取出还可以再分成三种情况:
(1) E不全为0或不全为1:
这时,浮点数就采用下面的规则表示,即指数E的计算值减去127(或1023),得到真实值,再将有效数字M前加上第一位的1
比如:
0.5(1/2)的二进制形式为0.1,由于规定正数部分必须为1,即将小数点右移1位,则为1.0 * 2^-1,其阶码为-1 + 127 = 126,表示为01111110(8位),而尾数1.0去掉整数部分为0,补齐0到23位,则其二进制表示为:
0 0111 1110 000 0000 0000 0000 0000 0000
(2) E全为0:
这时,浮点数的指数E等于1-127(或者1-1023)即为真实值,有效数字M不再加上第一位的1,而是还原为0.XXXXXX的小数。这样做是为了表示±0,以及接近于0的很小的数字
(3) E全为1:
这时,如果有效数字M全为0,表示±无穷大(正负取决于符号位S)
例:int n = 9;
float* pFloat = (float*)&n;
printf("%d", n);
printf("%f", *pFloat);
*pFloat = 9.0;
printf("%d", n);
printf("%f", *pFloat);
打印结果是什么?
答:9
0.000000
1091567616
9.000000
解释:9是正数,原反补相同,补码为0000 0000 0000 0000 0000 0000 0000 1001
但站在pFloat的角度认为内存中存的是浮点数编码,分成三部分:
0 00000000 000000000000000001001
E为全0的情况,E=1-127=-126
M=0.00000000000000000001001
故最后打印的是+0.000000000000000001*2^(-126)
再看后两个,刚才是以整数形式存进去,再以整型、浮点型打印的。现在以浮点数形式存进去,再以整型、浮点型打印的。
而以浮点数存,先写成二进制,再找S、E、M,拼成32位
9.0 → 1001.0 → 1.001 * 2^3
S=0,E=3,M=1.001(3 + 127 = 130,130二进制10000010)
所以二进制表示为0 10000010 00100000000000000000000
此时以整型打印是一个很大的正数,1091567616
最后以浮点数打印是9.000000
总结:相同类型的数据存储和打印是相同的
1132

被折叠的 条评论
为什么被折叠?



