#本章重点
详细解读数据在内存中是怎么存储的
数据类型
//整型
char //存的是ascii值
signed char //有符号的char类型
unsigned char //无符号的char类型
short
signed short
unsigned short
int
signed int
unsigned int
long
signed long
unsigned long
long long
signed long long
unsigned long long
int a=10;
//默认int前面有signed,其他的也是这样的
//浮点型
float
double
long double
//构造类型(自定义类型)
数组
结构体类型(struct)
枚举(enum)
联合体(union)
//指针类型
int*
char*
void*
.....
//空类型
void //没有具体指定的类型,通常用于函数返回值,函数参数,指针类型
整型在内存中的存储
变量的创建是要在内存中开辟空间的
int main()
{
int a = 20;
//00000000000000000000000000010100
//0x00000014
//14 00 00 00
int b = -10;
//整数在内存中是以补码存放的
//对于正整数来说,原码反码补码都相同
//对于负整数来说,补码是要计算的
//int类型是4个字节
//32个比特位
//10000000000000000000000000001010 原码
//11111111111111111111111111110101 反码(将原码的符号位不变,其他位按位取反)
//11111111111111111111111111110110 补码(反码加一)
//用16进制表示就是
//f6 ff ff ff
return 0;
}
为什么要用补码呢,使用补码可以将符号位和数值域统一处理,又cpu只有加法器
用原码计算1+(-1)
00000000000000000000000000000001 1的原码
10000000000000000000000000000001 -1的原码
10000000000000000000000000000010 得到的-2
用补码计算
00000000000000000000000000000001 1的补码
10000000000000000000000000000001 -1的原码
11111111111111111111111111111110 -1的反码
11111111111111111111111111111111 -1的补码
相加得到
100000000000000000000000000000000 得到33位的结果,舍掉最高位就得到0的补码
00000000000000000000000000000000
大、小端字节序存储
大端字节序存储
数据的低位保存在内存的高地址中,数据的高位保存在内存中的低地址处
小端字节序存储
数据的低位保存在内存的低地址中,数据的高位保存在内存中的高地址处
判断数据在内存中怎么存储的
int main()
{
int a = 0x11223344;
char c = (char)a; //这种方法是错误的,数值在char的范围内是不会发生改变的
if (c == 0x44)
{
printf("小端存储\n");
}
elsex
printf("大端存储\n");
return 0;
}
当前vs2019中是小端存储的
//写成函数
int check_sys()
{
int a = 1;
return *(char*)&a;
}
int main()
{
int ret = check_sys();
if (ret == 1)
{
printf("小端存储\n");
}
else
printf("大端存储\n");
return 0;
}
练习
a,b是一样的
11111111 -1的补码
%d表示int类型,char要整型提升
按原符号位提升
11111111111111111111111111111111 -1的补码
11111111111111111111111111111110 -1的反码
10000000000000000000000000000001 -1的原码(在屏幕上显示的)
c
无符号数整型提升前面补0
00000000000000000000000011111111 255
int main()
{
unsigned int i = 0;
for (i = 9; i >= 0; i--)
{
printf("%u\n", i);
}
return 0;
}
//无符号数>=0,条件恒成立,程序会变成死循环
这是因为当i等于129时,arr[130]=-130
100000000000000000000010000010 -130的原码
111111111111111111111101111101 反码
111111111111111111111101111110 补码
在截取
01111111 这是126
当i等于131时,arr[131]=-132
100000000000000000000010000100
111111111111111111111101111011
111111111111111111111101111011
再截取
01111011 这是123
以此类推,当i等于255时,arr[256]=-256
100000000000000000000100000000
111111111111111111111011111111
111111111111111111111100000000
截取
00000000 这是0
strlen是以'\0'停止的,'\0'的ascii码值是0
所以循环了255次,结果就是255
unsigned char i = 0;
int main()
{
for (i = 0; i <= 255; i++)
{
printf("hello world\n");
}
return 0;
}
//死循环
//当i=256时,i超过了unsigned char的取值范围了,i又变成0了
浮点数在内存中的存储
浮点型
float
double
long double
整型取值范围在limits.h中定义的
浮点型取值范围在float.h中定义的
十进制小数转换成二进制
整数转换就不说了
看小数部分
例如22.75
整数部分是10110
小数部分0.75
用小数部分乘以2,结果大于1,取1,小于1取0
0.75*2=1.5 取1
0.5*2=1.0 取1
结果就是10110.11
在算一个1.625
小数部分
0.625*2=1.25 取1
0.25*2=0.5 取0
0.5*2=1.0 取1
结果就是1.101
小数部分是按照顺序排列的
浮点型在内存中到底是怎么存储的呢
可以看出结果是大不相同的,这就说明了浮点型和整型在内存中的存储是不同的
浮点数在内存中的存储是由国际标准IEEE(电气和电子工程协会)754制定的
任意一个二进制浮点数V都可以表示成下面的形式:
(-1)^S * M * 2^E
(-1)^S 表示符号位,当S=0时,V为整数,当S=1时,V为负数
M代表有效数字,大于等于1,小于2
2^E表示指数位
例如5.5,二进制表示是101.1
用上面的标准就可以写成1.011*2^2
正数,(-1)^S等于0,S=0
1.011是M
E就是2
对于double型,S也是1个比特位,但是E是11个比特位,M是52个比特位
在科学计数法中是可以出现负数的,对于单精度浮点数来说,存入内存中的E要加上127,双精度浮点数加上1023,从内存中取出来的时候在减去
5.5在内存中的存放
5.5的二进制是101.1
1.011*2^2
s=0,e=2,m=011
01000000101100000000000000000000
16进制就是
0100 0000 1011 0000 0000 0000 0000 0000
40 B0 00 00
小端存储就是
00 00 B0 40
两种特殊情况
E全0
全为0,表示E等于1-127,这是一个无限接近于0的数字,即无穷小,此时M小数前的1不要了
E全为1
全为1,表示E等于255-127=128,这是一个非常大的数字,即无穷大
现在就可以解决最前面的题了
int main()
{
int n = 9;
//00000000000000000000000000001001
float* p = (float*)&n;
printf("n的值为:%d\n", n); //9
//以浮点数打印就会认为n里面放的是浮点数
//0 00000000 00000000000000000001001
//(-1)^0*(1-127)*(0.00000000000000000001001)
//最多打印小数点后面的六位,所以打印出来的是0.000000
printf("*p的值为:%f\n", *p);
*p = 9.0;
//现在是用浮点数的存储方式存储9.0
//1001.0 1.001*2^3
//s=0,e=3,m=011
//0 10000010 00100000000000000000000
//16进制就是
//0100 0001 0001 0000 0000 0000 0000 0000
//41 10 00 00
//小端存储
//00 00 10 41
printf("n的值为:%d\n", n); //当成整型打印,这是一个很大的数
printf("*p的值为:%f\n", *p); //9.000000
return 0;
}