Hello,各位小伙伴们上期我们讲解了C语言内存函数其中提及到了一个整形数字在内存中的存放是倒着的,这期小编将会带领大家了解数据在内存中的存储。
整形在内存中的存储
整形数据在内存中的存放是以补码的行是进行存放。
原因:
在计算机系统中,数值一律用补码来表示和存储。原因在于,使用补码,可以将符号位和数值域统一处理;同时,加法和减法也可以统一处理(CPU只有加法器)此外,补码与原码相互转换,其运算过程是相同的,不需要额外的硬件电路。
调试的时候,我们可以看到在a中的 0x11223344 这个数字是按照字节为单位,倒着存储的。
这涉及到大小端字节序的问题。
大小端字节序的判断
大端字节序:
是指数据的低位字节内容保存在内存的高地址处,而数据的高位字节内容,保存在内存的低地址处。
小端字节序:
是指数据的低位字节内容保存到内存的低地址处,而数据的高位字节内容,保存在内存的高地址处。
上述存储方式为小端存储方式。
OK让我们来看看如何判断一个数据的存储是大端字节序还是小端字节序存储。
#include<stdio.h>
int main()
{
int a = 1;
if ((*(char*)&a) == 1)
printf("小端");
else
printf("大端");
return 0;
}
对大小端字节序有了初步了解后让我们来看看几道例题:
练习
练习1
#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;
}//结果:-1 -1 225
char--signed char 的取值范围为-128~127,unsigned char 的取值范围为0~225。char到底是signed char 还是unsigned char 取决于编译器,但在VS上char默认为signed char。
题目分析:
(整形)-1的原码 10000000 00000000 00000000 00000001
(整形)-1的反码 11111111 11111111 11111111 11111110(整形)-1的补码 11111111 11111111 11111111 11111111
存储-1的变量a为char最多只能存储一个字节,按照小端字节序,存储最后一个字节11111111
同理signed char 和unsigned char 也都会存储11111111,也就是说存进去的值是一样但最后表现的值的大小不定。
在输出阶段printf中,%d是用来打印有符号整数的,需要对char进行整形提升,在进行整形提升时按着符号位进行补位。这时就需要具体看char的类型。
1、char 和signed char 存放-1的数据为11111111,在整形提升时按着符号位1进行补位,为
11111111 11111111 11111111 11111111。原码为10000000 00000000 00000000 00000001。
2、unsigned char 存放-1的数据也为11111111,由于变量为无符号类型,在整形提升时取0进行补位,为00000000 00000000 00000000 11111111,因为无符号类型的原反补相同。
翻译成二进制数字为255。
练习2
#include<stdio.h>
int main()
{
char a = -128;
printf("%u\n", a);
return 0;
}
分析:
a的二进制数原码为 10000000 00000000 00000000 10000000,补码为 11111111 11111111 11111111 10000000,存储在a中的为10000000,a的类型为有符号的char,在进行整形提升时为11111111 11111111 11111111 10000000同时无符号数的原反补码相同,%u打印有符号的整数,将其转化成十进制数后会非常大。
小伙伴试着分析这道题目
#include<stdio.h>
int main ()
{
char a = 128;
printf("%u",a);
return 0;
}//4,294,967,168
练习3
#include<stdio.h>
int main()
{
char a[1000];
int i = 0;
for (i = 0; i < 1000; i++)
{
a[i] = -1 - i;
}
printf("%d", strlen(a));
return 0;
}
strlen是求字符串长度的,需要找到' \0 '之前的字符。char类型的范围是-127~128;
我们试想一下使用上面的知识来解释为什么char类型的范围是-127~128。
![](https://i-blog.csdnimg.cn/direct/9f1dd0d22af949cd998906036e370c73.png)
从内存的存储上来看,从0到127之后连接到-128,即127下一位紧接着就是-128。同理,我们查看最后一位从11111111加1后会变成10000000,但一个char类型占一个字节8个byte位,会把1舍去,变成00000000,会惊讶的发现回到了首位0。
![](https://i-blog.csdnimg.cn/direct/dfcd1010fff24990a2c663a2c08f4e46.png)
分析:
arr[ i ]存储的值依次位-1,-2,,,,,-127,下一个值因为超出范围所以变成128紧接着位127,126,,,,,2,1,0之后为一个轮回。因为0对对应的字符为\0,所以停止读取。最后打印出来将为225。
练习4
#include<stdio.h>
unsigned char i = 0;
int main()
{
int count = 0;
for (i = 0; i <=255; i++)
{
printf("hello world\n");
}
return 0;
}
结果会死循环打印hello world
分析:
当i=255之后由于i的类型为unsigned char 加1后会变成0,会不断重复这个过程。
来看看我们的最后一题(稍微有点难度哦)
#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;
}
![](https://i-blog.csdnimg.cn/direct/443a074effc6479f9ce60f4565b8febe.png)
小编在这里不在详细的解释啦,各位小伙伴们发动思维看看最后的结果是什么。欢迎在评论区讨论。本期介绍就到这里啦,还有浮点数在内存中的存储后期会更新的,拜拜。