数据在内存中的存储
一、整数在内存中的存储
整数的2进制表示方法有三种,即 原码、反码和补码
正整数的原、反、补码都相同。
负整数的三种表示方法各不相同。
对于整形来说:数据存放内存中其实存放的是补码。
二、大小端字节序和字节序判断
当我们了解了整数在内存中存储后,我们调试看⼀个细节:
#include <stdio.h>int main()
{int a = 0x11223344;return 0;
}
调试的时候,我们可以看到在a中的 0x11223344 这个数字是按照字节为单位,倒着存储的。这是为什么呢?
2.1、什么是大小端?
上述概念需要记住,方便分辨大小端。
2.2、为什么会有大小端?
2.3、练习
2.3.1、练习1:
//代码1
#include <stdio.h>int check_sys()
{int i = 1;return (*(char *)&i);
}int main()
{int ret = check_sys();if(ret == 1){printf("⼩端\n");}else{printf("⼤端\n");}return 0;
}
//代码2
int check_sys()
{union{int i;char c;}un;un.i = 1;return un.c;
}
2.3.2、练习2:
#include <stdio.h>
int main()
{char a= -1;//1000 0000 0000 0000 0000 0000 0000 0001//1111 1111 1111 1111 1111 1111 1111 1110//1111 1111 1111 1111 1111 1111 1111 1111//存储在a中要发生截断//11111111 - a//1111 1111 1111 1111 1111 1111 1111 1111//1000 0000 0000 0000 0000 0000 0000 0000//1000 0000 0000 0000 0000 0000 0000 0001signed char b=-1;//11111111 - bunsigned char c=-1;//11111111 - c//0000 0000 0000 0000 0000 0000 1111 1111printf("a=%d,b=%d,c=%d",a,b,c);//-1 -1 255//%d - 十进制的形式打印有符号的整数return 0;
}
2.3.3、练习3:
#include <stdio.h>int main()
{char a = -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//10000000 - a//打印时发生整型提升//1111 1111 1111 1111 1111 1111 1000 0000printf("%u\n",a);//4,294,967,168//%u 是十进制的形式打印无符号的整数return 0;
}
#include <stdio.h>int main()
{char a = 128;//128 = 127 + 1 = -128printf("%u\n",a);return 0;
}
2.3.4、练习4:
#include <stdio.h>int main()
{char a[1000];//-128 ~ 127//-1 -2 -3 ... -128 127 126 125 ... 5 4 3 2 1 0 -1 -2 ... -128 127 126 ... 5 4 3 2 1//128 + 127 = 255int i;for(i=0; i<1000; i++){a[i] = -1-i;}printf("%d",strlen(a));//求字符串长度找的是\0,\0的ASCII码值是0,其实找的就是0//255return 0;
}
2.3.5、练习5:
#include <stdio.h>unsigned char i = 0;
int main()
{for (i = 0; i <= 255; i++){printf("hello world\n");}return 0;
}
#include <stdio.h>
#include <windows.h>int main()
{unsigned int i;for (i = 9; i >= 0; i--){printf("%u\n", i);Sleep(1000);//睡眠1秒}return 0;
}
2.3.6、练习6:
#include <stdio.h>int main()//x86环境下
{int a[4] = { 1, 2, 3, 4 };int* ptr1 = (int*)(&a + 1);int* ptr2 = (int*)((int)a + 1);printf("%x,%x", ptr1[-1], *ptr2);return 0;
}
三、浮点数在内存中的存储
3.1、练习:
#include <stdio.h>int main()
{int n = 9;float* pFloat = (float*)&n;printf("n的值为:%d\n", n);printf("*pFloat的值为:%f\n", *pFloat);*pFloat = 9.0;printf("num的值为:%d\n", n);printf("*pFloat的值为:%f\n", *pFloat);return 0;
}
①有些浮点数在内存中无法精确保存
②double类型的精度比float更高
③两个浮点数比较大小的时候,直接使用 == 比较可能存在问题!
比如:
5.6 -> 5.59999787897
f == 5.6
解决办法:给一个精度0.000001
if(abs(f - 5.6) <= 0.000001);//((f - 5.6) >= -0.000001) && ((f - 5.6) <= 0.000001)
3.2、浮点数的存储
要理解这个结果,⼀定要搞懂浮点数在计算机内部的表示方法。
根据国际标准IEEE(电气和电子工程协会) 754,任意⼀个⼆进制浮点数V可以表示成下面的形式:
举例来说:
十进制的5.0,写成⼆进制是 101.0 ,相当于 1.01×2^2 。
那么,按照上面V的格式,可以得出S=0,M=1.01,E=2。
十进制的-5.0,写成⼆进制是 -101.0 ,相当于 -1.01×2^2 。那么,S=1,M=1.01,E=2。
IEEE 754规定:
对于32位的浮点数,最高的1位存储符号位S,接着的8位存储指数E,剩下的23位存储有效数字M。
对于64位的浮点数,最高的1位存储符号位S,接着的11位存储指数E,剩下的52位存储有效数字M。
float类型浮点数内存分配
double类型浮点数内存分配
3.2.1、浮点数存的过程
IEEE 754 对有效数字M和指数E,还有⼀些特别规定。
至于指数E,情况就比较复杂。
3.2.2、浮点数取的过程
指数E从内存中取出还可以再分成三种情况:
E不全为0或不全为1
0 01111110 00000000000000000000000
E全为0
0 00000000 00100000000000000000000
E全为1
这时,如果有效数字M全为0,表示±无穷大(正负取决于符号位s)
0 11111111 00010000000000000000000
3.3、题目解析
0000 0000 0000 0000 0000 0000 0000 1001
显然,V是⼀个很小的接近于0的正数,所以用十进制小数表示就是0.000000。
再看第2环节,浮点数9.0,为什么整数打印是1091567616?
首先,浮点数9.0 等于⼆进制的1001.0,即换算成科学计数法是:1.001×2^3
0 10000010 001 0000 0000 0000 0000 0000