【c语言】数据在内存中的存储

[复制链接]
发表于 2025-5-4 10:03:17 | 显示全部楼层 |阅读模式
一、 大小端字节序

大端字节序:数据的低字节内容存放在内存的高地点处,数据的高字节内容存放在内存的低地点处,对于0x11223344

小端字节序:数据的低字节内容存放在内存的低地点处,数据的高字节内容存放在内存的高地点处,对于0x11223344

   

  • 什么是高字节和低字节
    对于十进制数字:1234,4是低位,1是最高位
    同理,对于十六进制:0x11223344,44是地点字节位,11是高字节位
  • 为什么会有大小端?
    数据在内存中的存储是以字节为单位的,char类型的变量占8个bit位,1个字节,但除了char类型之外有很多类型的变量大于1个字节,对于位数⼤于8位的处置惩罚器,例如16位或者32位的处置惩罚器,由于寄存器宽度⼤于⼀个字节,那么肯定存在着⼀个如何将多个字节安排的问题。因此就导致了⼤端存储模式和⼩端存储模式。
  二、练习

char默认是有符号的,usigned char 为无符号字符类型,char类型变量大小为1个字节,8个bit位
对于无符号类型,其范围为:0-255,是一个周期性的循环

对于有符号类型,其范围为:-128~127,也是一个周期性的循环

2.1. 练习一

  1. int main()
  2. {
  3. char a= -1;
  4. signed char b=-1;
  5. unsigned char c=-1;
  6. printf("a=%d,b=%d,c=%d",a,b,c);
  7. return 0;
  8. }
复制代码
  -1的补码为
11111111 11111111 11111111 11111111
char只能存储8个比特位,为11111111是补码,为-1;
b的值与a一样;
c是无符号,11111111作为补码,对应值为255
  2.2. 练习二

  1. int main()
  2. {
  3. char a = -128;
  4. printf("%u\n",a);
  5. return 0;
  6. }
复制代码
  -128
源码为:10000000 00000000 00000000 10000000
反码为:111111111 111111111 111111111 011111111
补码为:111111111 111111111 111111111 10000000
a中存储的为10000000
打印的是无符号整型,前面要补齐0
则补齐后补码为:00000000 00000000 00000000 10000000
反码为补码取反:11111111 11111111 11111111 01111111
源码为反码+1:11111111 11111111 11111111 10000000
结果为一个很大的值:4294967168
  2.3. 练习三

  1. int main()
  2. {
  3. char a[1000];
  4. int i;
  5. for(i=0; i<1000; i++)
  6. {
  7. a[i] = -1-i;
  8. }
  9. printf("%d",strlen(a));
  10. return 0;
  11. }
复制代码
  由于a是char类型,只能存储-128~127的范围,因此,循环开始后:
-1,-2,…-127,-128,127,126,125…,2,1,0 由于strlen到\0的位置停止计算,因此a的长度为128+127=255
  2.4. 练习四

  1. int main()
  2. {
  3.         int a[4] = { 1, 2, 3, 4 };
  4.         int* ptr1 = (int*)(&a + 1);
  5.         int* ptr2 = (int*)((int)a + 1);
  6.         printf("%x,%x", ptr1[-1], *ptr2);
  7.         return 0;
  8. }
复制代码
  对于ptr2,数组a在内存中存储的形式为小端存储: 01 00 00 00 02 00 00 00 03 00 00 00 04 00 00
00 a为首元素地点,强转成int后,+1就是+1
假如首元素地点为0x12ff40,强制转换成整型后+1后为0x12ff41,再将其转换成int*后,为地点,那么地点0x12ff40与0x12ff41相差一个字节,因此ptr2向后走了一个字节,其类型为int*,解引用后拿出的是4个字节,因此ptr2指向的内存空间数据为:
00 00 00 02,由于是小端存储,拿出后排列方式为02 00 00 00 按16进制打印出为0x02000000
  三、浮点数在内存中的存储方式

任意⼀个⼆进制浮点数V可以表⽰成下⾯的形式:

例如:
9.5表示成二进制为:1001.1,写成V的形式为:(-1)^0*1.0011*2^3
所以S=0,M=1.0011,E=3
IEEE 754规定:
对于32位的浮点数,最⾼的1位存储符号位S,接着的8位存储指数E,剩下的23位存储有效数字M;
对于64位的浮点数,最⾼的1位存储符号位S,接着的11位存储指数E,剩下的52位存储有效数字M;
以32位为例:

在存储的过程中,1<M<2,因此默认M的第一位总是1,可以被舍去,只生存小数点后的部分,比及读取的时候再把前面的1加上,如许做的目的是可以节省1个有效数字;对于指数E来说,在存入时候必须加上一个中心值,对于8位的E来说,中心值是127,对于11位的E来说,中心值为1023
   以9.5为例:S=0,M=1.0011,E=3,E+127为130,二进制为:10000010
在存入时候,M为00110 00000 00000 00000 000,所以,在存储在内存中的形式为:
0 10000010 00110000000000000000000
  浮点数读取的过程:
E不全为0或不全为1:指数E的计算值减去127(或1023),得到真实值,再将有效
数字M前加上第⼀位的1;
E全为0这时,浮点数的指数E等于1-127(或者1-1023)即为真实值,有效数字M不再加上第⼀位的1,⽽是还为0.xxxxxx的⼩数。如许做是为了表⽰±0,以及靠近于0的很⼩的数字;
E全为1这时,如果有效数字M全为0,表⽰±⽆穷⼤(正负取决于符号位s)
练习:
  1. int main()
  2. {
  3. int n = 9;
  4. float *pFloat = (float *)&n;
  5. printf("n的值为:%d\n",n);
  6. printf("*pFloat的值为:%f\n",*pFloat);
  7. *pFloat = 9.0;
  8. printf("num的值为:%d\n",n);
  9. printf("*pFloat的值为:%f\n",*pFloat);
  10. return 0;
  11. }
复制代码
  9在内存中的补码为00000000 00000000 00000000 00001001
上面两个printf函数内:站在pFloat的角度来看,补码中的数据是以浮点数的形式存储的,即S、E、M的方式存储,读出的值为0.00000000,这时候E全为0,表示很小的靠近于0的数字
下面两个printf函数内:9是以浮点数的形式存储的,二进制位1001.0,(-1)^0*1.001*2^3
S=0,E=3,M=001
0 10000010 0010000000000000000000
以整数形式拿出时候,是一个很大的数字,以浮点出取出时候,就是9.0
  


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
继续阅读请点击广告

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
回复

使用道具 举报

© 2001-2025 Discuz! Team. Powered by Discuz! X3.5

GMT+8, 2025-7-9 04:51 , Processed in 0.076634 second(s), 31 queries 手机版|qidao123.com技术社区-IT企服评测▪应用市场 ( 浙ICP备20004199 )|网站地图

快速回复 返回顶部 返回列表