1.整数在内存中的存储
1.1 原码,反码,补码
整数(占4个字节,即32个bit)的二进制表示方法有3种,即原码,反码,补码,三种表示方法均有符号位和数值位两部分
原码:直接将数值按照正负数的形式翻译成二进制得到的就是原码
反码:将原码符号位(最高位,0为正,1为负)不变,其余位按位取反得到反码
补码:反码+1得到补码 (补码得到原码也可以使用 取反,+1 的操作)
正整数的原,反,补码都相同,如下
int a = 10;
//00000000000000000000000000001010 - 原码
//00000000000000000000000000001010 - 反码
//00000000000000000000000000001010 - 补码
负整数的原,反,补码各不相同,如下
int b = -10;
//10000000000000000000000000001010 - 原码
//11111111111111111111111111110101 - 反码
//11111111111111111111111111110110 - 补码
对于整型来说:数据存放内存中其实存放的是二进制的补码
1.2 大小端问题
我们设置一个整型的n的地址为 0x11223344
#include <stdio.h>
int main()
{
int n = 0x11223344;//两个16进制位表示8个2进制位
return 0;
}
当调试查看内存的存放的时候,发现地址存放顺序是反的,为 44 33 22 11,我们需要注意:
1.数据在内存中储存的是二进制的补码
2.在调试窗口观察时,为方便显示,显示的是16进制
3.存放顺序是倒着的
1.2.1大小端字节序存储(以字节讨论)
我们上面的地址 0x11223344 可以看成 0x 11 22 33 44 ,在10进制中比如123这个数 ,3是个位,2是十位,1是百位,右边是低位,左边是高位,可以理解为右边是小端,左边是大端,在16进制中也一样,44是低位,11是高位
大端字节序存储:把一个数据的低位字节的内容储存到高地址处,把高位字节的内容储存到低地址处
小端字节序存储:把一个数据的低位字节的内容储存到低地址处,把高位字节的内容储存到高地址处
所以当前存储方式为 小端字节序存储
1.3 相关练习
练习1
设计一个程序判断当前机器的字节序
参考答案
#include <stdio.h>
int main()
{
int a = 1;
if (*(char*)&a == 1) // &a :01 00 00 00
printf("小端");
else // &a :00 00 00 01
printf("大端");
return 0;
}
练习2
下面代码的输出结果是什么?
#include <stdio.h>
int main()
{
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类型占1个字节,就是8个bit位,取的是后8位;
signed char是有符号char,最高位是符号位,其余7位是数值位,正号补码范围是00000000(0)~01111111(127),负号补码范围是10000000(-128)~11111111(-1),为了不浪费数据,补码为10000000的默认为是-128,所以 signed char的取值范围是-128~127; unsigned char是无符号char,所有位都是数值位,从00000000(0)~11111111(255),所以unsigned char的取值范围是0~255;
用%d打印,类型需要提升为整型,signd补齐高位时看符号位,符号位是1补1,是0补0,unsignd全补0
练习3
下面程序结果是什么?
#include <stdio.h>
int main()
{
char a[1000];
int i;
for (i = 0; i < 1000; i++)
{
a[i] = -1 - i;
}
printf("%d", strlen(a));
}
答案
255
解析
strlen计算的是‘\0’之前的元素个数,'\0'的ASCII码值是0;
2. 浮点数在内存中的存储
任意一个二进制浮点数V都可以表示成下面的形式:
比如
所以浮点数的存储其实存的是S,M,E相关的值
对于32位的浮点数(float),最高1位存储符号位S,后8位存储指数E,剩下的23位存储有效数字M
对于64位的浮点数(double),最高1位存储符号位S,后11位存储指数E,剩下的52位存储有效数字M
2.1 浮点数存的过程
有效数字M
因为,所以M可以写成1.xxxxxxde形式,其中xxxxxx表示小数部分
在计算机内部保存M时,默认这个数的第一位总是1,因此可以舍去,只保留后面的xxxxxx部分,如,保存1.01时,只保存小数点后的01,等读取时再把小数点前的1加上, 这样做的目的是节省1位有效数字,以32位浮点型为例,留23位保存M,将第一位舍去后,等于可以保留24位有效数字
指数E
E为一个无符号整数(unsigned int),这意味着,如果E为8位,它的取值范围为0~255,如果E为11位,范围是0~2047,但是科学计数法中E是可以出现负数的,所以规定存入内存时E的真实值必须加上一个中间值,对于8位E,这个中间值是127,对于11位,这个值是1023,比如,2^10的E是10,保存32位浮点数时,必须保存成10+127=137,即10001001
2.2 浮点数取的过程
指数E从内存中取出可分为3种情况
1)E不全为0,或E不全为1
此时指数E的计算值减去127(或1023),得到真实值,再将有效值M前加上第一位的1
如,0.5
十进制:0.5
二进制:0.1
由于正数部分必须为1,则
将小数点右移1位:1.0*2^(-1)
其补码为:(-1)+127=126
表示为:01111110
位数去掉整数部分为0
补齐0到23位:0 01111110 00000000000000000000000
2)E全为0
此时指数E等于1-127(或1-1023)为真实值,有效数字M不再加上第一位的1,而是还原为0.xxxxxx的小数,这样是为了表示,以及接近于0的很小的数字
0 00000000 00010000000000000000000
3)E为全1
此时代表正负无穷大的数字
0 11111111 00010000000000000000000
2.3相关练习
输出结果是?
#include <stdio.h>
int main()
{
int n = 9;
float* p = (float*)&n;
printf("n的值为:%d\n", n);
printf("*p的值为:%f\n", *p);
*p = 9.0;
printf("n的值为:%d\n", n);
printf("*p的值为:%f\n", *p);
return 0;
}
答案:
n的值为:9
*p的值为:0.000000
n的值为:1091567616
*p的值为:9.000000
解析:
以整型视角存储9
00000000 00000000 00000000 00001001 //9的二进制
0 00000000 000000000000000000001001 //p认为是float类型
当内存中E全为0时,这个数字无限接近0,用%f打印小数点后6为,结果为0.000000
以float视角存储9.0
1001.0 //二进制
1.001*2^3 //化为二进制科学计数法
此时S=0,M=1.001,E=3
0 10000010 00100000000000000000000 //浮点数视角
01000001 00010000 00000000 00000000 //整型视角
将上面的二进制用%d打印出来就是一个很大的数字
本次分享就到这里,感谢阅读!
标签:存储,字节,int,浮点数,补码,基础知识,char,内存,C语言 From: https://blog.csdn.net/2402_82757055/article/details/136760349