C语言底层学习(4.数据在内存中的存储)
- 🌈🌈🌈这里是say-fall分享,感兴趣欢迎三连与评论区留言
- 🔥🔥🔥专栏:《C语言入门知识点》、《C语言底层》
- 💪💪💪格言:今天多敲一行代码,明天少吃一份苦头
前言:
有人说学编程其实就是在学内存,如果对内存的理解不够就很容易写出莫名其妙的代码,导致错误的结果,今天我们就来看一下我们常见的一些数据,如:整数和浮点数在内存中是如何存储的,感兴趣的小伙伴快来围观吧~
注意:
本篇的练习解析全部都放在了《配套《数据在内存中的存储》》
文章目录
- 前言:
- 注意:
- 正文:
- 1. 整数在内存中的存储
- 1.1 二进制与原、反、补码
- 1.2 大小端字节序
- 1.3 为什么有⼤⼩端?
- 1.4 练习
- 1.4.1 练习1
- 1.4.2 练习2
- 1.4.3 练习3
- 1.4.4 练习4
- 1.4.5 练习5
- 1.4.6 练习6
- 1.4.7 练习7
- 1.4.8 练习8
- 2. 浮点数在内存中的储存
- 2.1 浮点数如何在内存里存储
- 2.1.1 练习9
- 2.1.2 详细说明:
正文:
1. 整数在内存中的存储
1.1 二进制与原、反、补码
之前已经在《二进制与原、反、补码》中讲解过整数为什么要有二进制,并且计算机中的整数都是以补码的形式存储的
大家可以自行跳转《二进制与原、反、补码》查看
1.2 大小端字节序
在详细的讲解什么是大小端字节序之前,我们先来看一个代码调试中容易被忽略的小细节:
很容易就能发现这里的地址由低到高位是44 33 22 11 排序的,然后这里的a由低位(可以理解为二进制的个位)到高位也是44 33 22 11 排序的,我们把这种排序方式称为小端字节序
反之,如果地址由低到高位是11 22 33 44 的话,则称为大端字节序
具体概念为:
- ⼤端(存储)模式:
是指数据的低位字节内容保存在内存的⾼地址处,⽽数据的⾼位字节内容,保存在内存的低地址处。 - ⼩端(存储)模式:
是指数据的低位字节内容保存在内存的低地址处,⽽数据的⾼位字节内容,保存在内存的⾼地址处。
1.3 为什么有⼤⼩端?
为什么会有⼤⼩端模式之分呢?
- 这是因为在计算机系统中,我们是以字节为单位的,每个地址单元都对应着⼀个字节,⼀个字节为8bit位,但是在C语⾔中除了8bit的
char
之外,还有16bit的short
型,32bit的long
型(要看具体的编译器),另外,对于位数⼤于8位的处理器,例如16位或者32位的处理器,由于寄存器宽度⼤于⼀个字节,那么必然存在着⼀个如何将多个字节安排的问题。因此就导致了⼤端存储模式和⼩端存储模式。 - 例如:⼀个 16bit 的
short
型x
,在内存中的地址为0x0010
,x
的值为0x1122
,那么
0x11
为⾼字节,0x22
为低字节。对于⼤端模式,就将0x11
放在低地址中,即0x0010
中,0x22
放在⾼地址中,即0x0011
中。⼩端模式,刚好相反。我们常⽤的X86
结构是⼩端模式,⽽KEIL C51
则为⼤端模式。很多的ARM,DSP都为⼩端模式。有些ARM处理器还可以由硬件来选择是⼤端模式还是⼩端模式。
1.4 练习
1.4.1 练习1
- 请设计⼀个⼩程序来判断当前机器的字节序
很显然,对于这题来说,要想知道字节序,只需要识别一下最小和最大的地址处的字节大小就好了
例如:
int main()
{int a = 0x11223344;if (*(char*)&a > *((char*)&a+3))//假设低处地址是44(即小端模式){printf("小端");}else{printf("大端");}return 0;
}
在x86环境下,运行结果为:
小端
或者换一种方法:
//代码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为代码1的化简版
1.4.2 练习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);return 0;
}
运行结果:
a=-1,b=-1,c=255
1.4.3 练习3
#include <stdio.h>
int main()
{char a = -128;printf("%u\n",a);return 0;
}
运行结果:
4294967168
1.4.4 练习4
#include <stdio.h>
int main()
{char a = 128;printf("%u\n",a);return 0;
}
运行结果:
4294967168
1.4.5 练习5
#include <stdio.h>
int main()
{char a[1000];int i;for(i=0; i<1000; i++){a[i] = -1-i;}printf("%d",strlen(a));return 0;
}
运行结果:
255
1.4.6 练习6
#include <stdio.h>
unsigned char i = 0;
int main()
{for(i = 0;i<=255;i++){printf("hello world\n");}return 0;
}
运行结果:
hello world
hello world
hello world
...
//死循环
1.4.7 练习7
#include <stdio.h>
int main()
{unsigned int i;for(i = 9; i >= 0; i--){printf("%u\n",i);}return 0;
}
运行结果:
//对于运行结果想必大家也猜到了
9
8
7
6
5
4
3
2
1
0
4294967295
4294967294
//...循环
1.4.8 练习8
#include <stdio.h>
//X86环境 ⼩端字节序
int main()
{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;//%x意思是16进制输出
}
运行结果:
4,2000000
2. 浮点数在内存中的储存
2.1 浮点数如何在内存里存储
2.1.1 练习9
#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;
}
运行结果:
n的值为:9
*pFloat的值为:0.000000
num的值为:1091567616
*pFloat的值为:9.000000
2.1.2 详细说明:
说明:
根据国际标准IEEE(电⽓和电⼦⼯程协会)754,任意⼀个⼆进制浮点数V可以表⽰成下⾯的形式:
IEEE 754规定:
- 对于32位的浮点数,最⾼的1位存储符号位S,接着的8位存储指数E,剩下的23位存储有效数字M
- 对于64位的浮点数,最⾼的1位存储符号位S,接着的11位存储指数E,剩下的52位存储有效数字M
即:
如图,float
类型浮点数在内存中是这样分配的
- 这样的话我们就弄清楚了浮点数在内存中的存储,具体的题目解析详看《配套《数据在内存中的存储》》
- 本节完…