【c语言】数据在内存中的存储--大小端字节序和字节序判断

数据在内存中的存储


1.整数在内存中的存储

  1. 整数的2进制表⽰⽅法有三种,即 原码、反码和补码
  2. 有符号的整数,三种表⽰⽅法均有符号位和数值位两部分,符号位都是⽤0表示“正”,⽤1表示“负”,最⾼位的⼀位是被当做符号位,剩余的都是数值位。
  3. 正整数的原、反、补码都相同
  4. 负整数的三种表⽰⽅法各不相同
    1. 原码:直接将数值按照正负数的形式翻译成⼆进制得到的就是原码
    2. 反码:将原码的符号位不变,其他位依次按位取反就可以得到反码
    3. 补码:反码+1就得到补码
  5. 对于整形来说:数据存放内存中其实存放的是补码
    1. 在计算机系统中,数值⼀律⽤补码来表⽰和存储。
    2. 原因在于,使⽤补码,可以将符号位和数值域统⼀处理;
    3. 同时,加法和减法也可以统⼀处理(CPU只有加法器)此外,补码与原码相互转换,其运算过程是相同的,不需要额外的硬件电路;

2.大小端字节序和字节序判断

当我们了解了整数在内存中存储后,我们调试看⼀个细节:
​​​​​​
#include <stdio.h>

int main()
{
	int a = 0x11223344;

	return 0;
}
调试的时候,我们可以看到在a中的 0x11223344 这个数字是按照字节为单位,倒着存储的。这是为什么呢?
  1. 什么是⼤⼩端?
    1. 其实超过⼀个字节的数据在内存中存储的时候,就有存储顺序的问题,按照不同的存储顺序,我们分为⼤端字节序存储和⼩端字节序存储,下⾯是具体的概念:
  2. 为什么有⼤⼩端?
    1. 这是因为在计算机系统中,我们是以字节为单位的,每个地址单元都对应着⼀个字节,⼀个字节为8bit 位,但是在C语⾔中除了8 bit 的 char 之外,还有16 bit 的 short 型,32 bit 的 long 型(要看具体的编译器),另外,对于位数⼤于8位的处理器,例如16位或者32位的处理器,由于寄存器宽度⼤于⼀个字节,那么必然存在着⼀个如何将多个字节安排的问题。因此就导致了⼤端存储模式和⼩端存储模式。
    2. 例如:⼀个 16bit short x ,在内存中的地址为 0x0010 x 的值为 0x1122 ,那么0x11 为⾼字节, 0x22 为低字节。对于⼤端模式,就将 0x11 放在低地址中,即 0x0010 中,0x22 放在⾼地址中,即 0x0011 中。⼩端模式,刚好相反。我们常⽤的 X86 结构是⼩端模式,⽽KEIL C51 则为⼤端模式。很多的ARM,DSP都为⼩端模式。有些ARM处理器还可以由硬件来选择是⼤端模式还是⼩端模式。
  3. 练习
    1. 请简述⼤端字节序和⼩端字节序的概念,设计⼀个⼩程序来判断当前机器的字节序。(10分)-百度笔试题
    2. //代码1
      #include <stdio.h>
      
      int check_sys()
      {
      	//1的源码:00000000 00000000 00000000 00000001
      	//正数的原反补相同
      	int i = 1;
      
      	//int---4个字节大小
      	//由于i是整形数据,首先取出i的地址,强制类型转换为char *访问一个字节的数据
      	//返回0就证明是计算机是大端存储,返回1则相反
      	return (*(char*)&i);
      }
      
      int main()
      {
      	int ret = check_sys();
      
      	if (ret == 1)
      	{
      		printf("小端\n");
      	}
      	else
      	{
      		printf("大端\n");
      	}
      
      	return 0;
      }
    3. //代码2
      #include <stdio.h>
      
      int check_sys()
      {
      	union
      	{
      		int i;
      		char c;
      	}un;
      
      	un.i = 1;
      
      	return un.c;
      }
      
      int main()
      {
      	int ret = check_sys();
      
      	if (ret == 1)
      	{
      		printf("小端\n");
      	}
      	else
      	{
      		printf("大端\n");
      	}
      
      	return 0;
      }

      通过联合体访问同一块空间,因为i和c占用同一块空间,得出大小端存储

练习1

#include <stdio.h>

int main()
{
	//-1的源码:10000000 00000000 00000000 00000001
	//-1的反码:11111111 11111111 11111111 11111110
	//-1的补码:11111111 11111111 11111111 11111111
	//由于a是char类型,数据截断---11111111
	//打印a使用的是%d类型--整形类型--会将数据补齐--补符号位--11111111 11111111 11111111 11111111
	//将a的补码转换为源码进行打印--10000000 00000000 00000000 00000001--打印-1
	char a = -1;

	//和上面char类型一样的原理--打印-1
	signed char b = -1;

	//-1的源码:10000000 00000000 00000000 00000001
	//-1的反码:11111111 11111111 11111111 11111110
	//-1的补码:11111111 11111111 11111111 11111111
	//由于c是unsigned char类型,数据截断---11111111
	//打印的时候会把c看作无符号字符类型8位数据
	//数据补齐--高位补0--00000000 00000000 00000000 11111111
	//正数的原反补相同:所以会打印00000000 00000000 00000000 11111111--255
	unsigned char c = -1;

	printf("a=%d,b=%d,c=%d", a, b, c);

	return 0;
}

练习2

#include <stdio.h>

int main()
{
	//-128的源码:10000000 00000000 00000000 10000000
	//-128的反码:11111111 11111111 11111111 01111111
	//-128的补码:11111111 11111111 11111111 10000000
	//a是char型数据--存储时发生数据截断---10000000
	//将10000000高位使用1补齐(由于char是有符号浮点型)---11111111 11111111 11111111 10000000
	//使用%u进行打印数据时,打印的是无符号整型--相当于把上面一行数据当成整形进行打印
	//正数原反补相同,直接打印11111111 11111111 11111111 10000000
	char a = -128;

	printf("%u\n", a);

	return 0;
}

练习3

#include <stdio.h>

int main()
{
	//128的源反补码:00000000 00000000 00000000 10000000
	//a是char型数据--存储时发生数据截断---10000000
	//将10000000高位使用1补齐(由于char是有符号浮点型)---11111111 11111111 11111111 10000000
	//使用%u进行打印数据时,打印的是无符号整型--相当于把上面一行数据当成整形进行打印
	//正数原反补相同,直接打印11111111 11111111 11111111 10000000
	char a = 128;

	printf("%u\n", a);

	return 0;
}

练习4

#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次就会被赋值一个0,strlen函数也就会停止计算长度,所以打印出来的是255

  • 10
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值