数据在内存中的存储
数据在内存中的存储
- 一、整数在内存中的存储
- 二、大小端字节序和字节序判断
- 1.大小端
- 2.练习
- 三、浮点数在内存中的存储
- 1.浮点数的存储
- 1.1浮点数存的过程
- 1.2浮点数取的过程
- 2.题目解析
一、整数在内存中的存储
对于整型来说,数据存放内存中其实存放的是补码。
二、大小端字节序和字节序判断
1.大小端
超过一个字节的数据在内存中存储的时候,就有存储顺序的问题,按照不同的存储顺序,分为大端字节序存储和小端字节序存储:
eg:0x11223344
- 大端(存储)模式:是指数据的低位字节内容保存在内存的高地址处,而数据的高位字节内容,保存在内存的低地址处。11 22 33 44
- 小端(存储)模式:是指数据的低位字节内容保存在内存的低地址处,而数据的高位字节内容,保存在内存的高地址处。44 33 22 11
2.练习
1.设计一个小程序来判断当前机器的字节序。
//代码1
#include<stdio.h>
int check_sys()
{
int i=1;
return (*(char*)&i);
//先取出1在内存中的存储,强转为char*可解引用取出第一个字节
}
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;
}
//union允许i和c共享同一块内存,c访问的是i的最低字节
int main()
{
char a = -1;
//10000000000000000000000000000001
//11111111111111111111111111111110
//11111111111111111111111111111111
//char1字节:11111111
//char默认signed,升int以符号位补齐
//11111111111111111111111111111111
signed char b = -1;//同char
unsigned char c = -1;
//11111111
//unsigned升int以0补齐
//00000000000000000000000011111111
printf("a=%d,b=%d,c=%d,a,b,c);
return 0;
}
输出结果:a=-1,b=-1,c=255
3.
//3.1
int main()
{
char a = -128;
//10000000000000000000000010000000
//11111111111111111111111101111111
//11111111111111111111111110000000
//10000000
//char整型提升:
//11111111111111111111111110000000
printf("%u\n",a);//4294967168
return 0;
}
//3.2
int main()
{
char a = 128;
//00000000000000000000000010000000
//10000000
//可得到与上题相同结果
printf("%u\n",a);
return 0;
}
int main()
{
char a[1000];
int i;
for(i=0;i<1000;i++)
{
a[i] = -1-i;
//-1,-2,-3...-128,127,126...1,0
}
printf("%d",strlen(a));//\0的ASCII码是0,所以strlen到0结束,255
return 0;
}
由图可得,-1后-128的下一个数是127。
5.
//5.1
unsigned char i = 0;//无符号char类型范围0~255
int main()
{
for(i=0;i<=255;i++)//条件恒成立,死循环打印下面字符串
{
printf("hello world\n");
}
return 0;
}
//5.2
int main()
{
unsigned int i;//无符号整型
for(i=9;i>=0;i--)//同样死循环
{
printf("%u\n",i);
}
return 0;
}
//x86环境 小端字节序
int main()
{
int a[4] = {1,2,3,4};
int *ptr1 = (int *)(&a+1);//4
int *ptr2 = (int *)((int)a+1);
printf("%x,%x,ptr1[-1],*ptr2);
return 0;
}
这里a是指数组首元素地址,指向01000000的地址被强转为int类型加一,则指向下一个字节,再转为int*解引用,一次取出的是四个字节int的值,小端存储打印02000000。
三、浮点数在内存中的存储
1.浮点数的存储
浮点数在计算机内部的表示方法,根据国际标准IEEE754,任意一个二进制浮点数V可以表示成下面的形式:
- (-1)^S表示符号位,当S=0,V为正数;当S=1,V为负数
- M表示有效数字,M是大于等于1,小于2的
- 2^E表示指数位
eg:-5.0 -> -101.0 -> -1.01*2^2
S=1,M=1.01,E=2。
对于32位浮点数,最高1位存储符号位S,接着的8位存储指数E,剩下的23位存储有效数字M;
对于64位浮点数,最高1位存储符号位S,接着的11位存储指数E,剩下的52位存储有效数字M。
1.1浮点数存的过程
M:
IEEE 754规定,在计算机内部保存M时,默认这个数的第一位总是1,因此可以被舍去,只保存后面的效数部分,等到读取的时候再把第一位的1加上去,目的是节省1位有效数字。
E:
首先E为一个无符号整数,但在实际中会出现E为负数的情况,因此规定存入内存时E的真实值还必须加上一个中间值,8位E:+127;11位E:+1023。
1.2浮点数取的过程
一共三种情况:
1.2.1 E不全为0或不全为1
E减去127,再将有效数字M前加上第一位的1。
eg:0.5 ->0.1(二进制形式) ->1.0*2^(-1)
E:-1+127:126 ->01111110
最终得到:1 01111110 00000000000000000000000
1.2.2 E全为0
这时,浮点数的指数E等于1-127(或1-1023)即为真实值,有效数字M不再加上第一位的1,而是还原为0.xxxxxx的小数,表示±0,以及接近于0的很小的数字。
1.2.3 E全为1
这时,如果有效数字M全为0,表示±无穷大(正负取决于符号位s)。
2.题目解析
int main()
{
int n = 9;
float *pFloat = (float *)&n;
printf("n %d\n",n);//9
printf("*pFloat %f\n",*pFloat);
*pFloat = 9.0;
printf("num %d\n",n);
printf("*pFloat %f\n",*pFloat);//9.0
return 0;
}
当数值或指针的类型与打印的类型一致时,会出现希望得到的结果。
- 第二问:00000000 00000000 00000000 00001001
将原来9的二进制序列以浮点数的形式拆分:0 00000000 00000000000000000001001
由上得:E全为0,即结果为0.000000 - 第三问:9.0 ->1001.0 ->1.001*2^3
S=0,E=3(+127=130),M=1.001(去1->.001)
0 10000010 00100000000000000000000
使用计算器打印最终结果是1091567616。