本章重点
1.数据类型详细介筛
2.整型在内存中的存储:原码 反码 补码
3.大小端字节序介绍及判断
4.浮点型在内存中的存储解析
数据类型介绍
char//字符型
short//短整型
int//整型
long//长整型
long long//更长的整型
float//单精度浮点型
double//双精度浮点型
整型家族
char//char在内存中存储的是ASCAII值
unsigned char
signed char
short
unsigned short[int]
sugned short[int]
int
unsigned int
signed int
long
unsigned long
signed long
浮点型家族
float
double
构造类型
数组类型
结构体类型 struct
枚举类型 enum
联合类型 union
指针类型
int*
char*
float*
void*
整型在内存中的存储
原码、反码、补码
计算机中的有符号数有以上三种表示方法
三中表示方法都由符号位和数值位组成,符号位0为正,1为负,正数的原、反、补相同,且内存中存的是二进制数的补码
直接把十进制的负数转换成有符号位的二进制即可
-10
10000000|00000000|00000000|00001010//原码
11111111|11111111|11111111|11110101//补码,符号位不变,其余位置反
11111111|11111111|11111111|11110110//反码=补码+1
FF|FF|FF| F6 //将补码转换成16进制
20
0加粗样式0000000|00000000|00000000|00010100 原 反 补码
00|00|00|14 转换成16进制
可以发现,我们计算的补码和内存中有些许顺序上的出入,这是为什么呢?
关于大小端
大端存储模式,是指数据的低位保存在内存的高地址中,而数据的高位保存在内存的低地址中
小端存储模式,是指数据的低位保存在内存的低地址中,而数据的高位保存在内存的高地址中
数据存储的有关题目
题目一:输出什么?
int main()
{
char a = -1;
signed char b = -1;
unsigned char c = -1;
printf("%d\n%d\n%d\n",a,b,c);
return 0;
}
解释
char是一个字节8bit,将-1存入三个类型的char内
-1的原码
10000000 |00000000 |00000000|00000001
11111111 |11111111 |11111111 |11111110 反码
11111111 |11111111 |11111111 |11111111补码
所以,将32个bit的整型-1存入char 会发生截断,将低8位11111111(补码)存入a b c
由于打印的时候打印的是%d,所以需要做整型提升,将8bit的 a b c提升至32位才能打印
对于a来说,有符号数11111111(补码),整型提升是将符号位前扩至32位变成了
11111111|11111111|11111111|11111111 (-1的反码),所以打印a是-1
对于b来说,b也是有符号数所以和a一样,整型提升至全1,所以打印-1
对于c才说,其是无符号位,所以用0填充,变成:
00000000 |00000000 |00000000 |11111111 ——255
所以c打印255
题目二
题目三
解释
可以看到,函数进入了死循环,一直在打印i,我们预期的是打印9-0后停止,但是实际上确实打印了9-0,但是继续打印了更大的数字,说明0之后i变成了相应的数字。
这是因为i是一个无符号数,变成0时再减1变成-1
-1相应的补码是11111111 11111111 11111111 11111111
在有符号数看来这是-1,但在无符号数 i 看来,这是最大的32位整数,所以for循环并未停止
题目四
解释
char a是一个有符号数,取值范围是**-128-127**
strlen 是计算字符串的长度,遇到\0就停止计算并返回数值
对于有符号字符char来说,
其加法计算顺数如下:
00000000→00000001→00000010→00000011→…→01111111→→…↓
↑-----0-----------1---------------2----------------3----------…-------127------------↓
↑11111111←11111110←…←10000010←10000001←10000000-----←
-----(-1)----------(-2)--------------(-126)---------(-127)----…—(-128)--------
减法计算顺序:
00000000←00000001←00000010←00000011←…←01111111←←…↑
↓-----0-----------1---------------2----------------3----------…-------127------------↑
↓11111111→11111110→…→10000010→10000001→10000000-------←
-----(-1)----------(-2)--------------(-126)---------(-127)----…—(-128)--------
把计算顺序写成闭环圈的形式,顺时针是加,逆时针是减
所以,a[i]的值依次是-1 -2 -3 -4 -5…-128 127 126 125…3 2 1 0 -1 -2…
但是,strlen只计算到第一个0 所以0前面一共有128+127 =255个字符,所以打印了255
题目五
解释
程序应该是死循环一直打印,这是因为,无符号的char i取值范围是0-255,当255+1时,就变成了0
浮点型在内存中的存储
float double long double
常见的浮点数:3.14 1E10(1.0x10^10)
题目六,输出什么
n和*pFloat在内存中应该是一个数,但是用整数%d和浮点数%f取出来的时候结果不同,这就涉及到了浮点数在计算机内部的表示方法
IEEE规定,二进制数字Num可表示成:
(-1) ^ S*M * 2^E
(-1) ^ S是符号位,表示-1的幂,S取0或1
M是有效数字,取[1,2)
2^E是指数位,表示2的E次方
例如:
9.0 十进制
1001.0二进制
(-1) ^ 0 1.0012^3, 表示1.001乘2的三次方
S=0
M=1.001
E=3
0.5十进制
0.1二进制
(-1) ^ 01.02^-1
S=0
M=1.0
E=-1
对于32位的浮点数folat,最高的1位表示符号位S,紧接着8位表示会指数E,剩下M区23位为有效数字
注意
.
**1.**E是无符号unsigned取值[0,255],但是实际上有的小数指数部分可能是负的,比如0.5=(-1) ^ 01.02^-1,E= -1,所以-1不能直接存入E中,而是要加上[0,255]的中位数127,变成126,再存入E区中,取出来的时候再减127
.
**2.**再就是M区,我们知道有效数字的第一个数字一定是1所以M区只存储小数部分,可以提高一些精度
从E区取出来数,还可以分成下面三种情况:
E不全为0或1
E就要减127才是真是的数值
E是全0
所以指数部分真实值是-127,所以真实的数非常小无限接近0,有效数字M不再加上默认的整数部分1,而是还原为0.xxxxx的小数
E全是1
所以真实的指数部分是128,所以真实的数非常大