嵌入式软件工程师笔试面试题分类汇总——字节序(大小端)& 比特序(LSB、MSB)

1. 字节序——大小端

1.1 简介

大端(Big-Endian): 数据字节——>位地址,数据低字节——>高位地址;
小端(Little-Endian): 数据字节——>位地址,数据低字节——>高位地址;

防止记混了可以只记住小端是高对高,其他的自己可以推出来;
或者你可以记住大端模式符合我们的阅读习惯(至于怎么符合,看下图);
插一句,小端模式其实是符合我们的逻辑思维,低字节放在低地址,高字节放在高地址(emmm…怕记混了当我没说>_<)

注1:计算机在内存中存放数据的顺序都是从低地址到高地址,大小端的差异只是体现在首先取低字节的数据存放在低地址还是取高字节的数据存放在低地址;此外,所谓的大小端只是数据在存储时的表现,而非在寄存器中参与运算的表现;

常用的x86结构都是小端模式,而大部分DSP,ARM也是小端模式,而KEIL C51则为大端模式;

1.2 图示

举个栗子,当我们存放一个数据为int类型时,他需要占用4个字节,如图所示,int a = 0x12345678, &a = 0x0042ff11(懂意思就好,&a是不能做左值的,演示所用,勿喷),那么这个a在内存中到底如何存放呢?
在这里插入图片描述
如上图,现在应该可以明确感受到所谓的大端模式符合我们的阅读习惯了吧

注2:只有多字节数据存储时才会考虑大小端,如果一个数据只占一个字节,比如char类型的字符,那这个字节的内存中就保存字符对应的ASCII码。
当然,大小端的出现不仅仅是因为多字节数据的存储问题,还有一个原因是:处理器的差异性,对于16/32位的处理器,由于寄存器的宽度大于一个字节,那么必然存在一个如何将多个字节安排的问题。

这里顺带提下,int、char等数据类型是告诉编译器从内存的某个地址开始读几个字节的数据,比如char类型是读一个字节,int类型是4个字节,当然了,有些类型在32/64位的机器上不一样,这里就不展开讨论了,下次有机会再详细介绍。

2. 比特序(位序)

2.1 简介

之前讲的大端小端是针对字节序的,那么可能有的小盆友就要举手问了,那我一个字节的数据在内存中存放时是从左往右还是从右往左啊?这就牵扯到比特序的概念,也叫位序。
一个字节8个比特位,从第0位到第7位,比特序就是用来描述比特位在字节中的存放顺序的
引入两个概念:
  LSB:最低有效位;
  MSB:最高有效位;
比特序分为两种:
LSB 0位序:字节的第0位存放数据的LSB,即数据的最低位存放在字节的第0位;
MSB 0位序:字节的第0位存放数据的MSB,即数据的最高位存放在字节的第0位;

2.2 图示

no pic you say j8! 继续举个栗子吧…
假设有一个十进制的数:174
其对应的二进制数:1010 1110
则:

  1. LSB 0位序下,其存储形式如下图:
    在这里插入图片描述

数据流的顺序为01110101

  1. MSB 0位序下,其存储形式如下图:在这里插入图片描述

数据流的顺序为10101110

字节序是小端的CPU通常其位序位LSB 0,但是字节序是大端的CPU采用的位序既有MSB 0,也有LSB 0的;

3. 小知识点

  1. 所有网络协议都采用大端的方式来传输数据,所以也称大端方式位网络字节序;
  2. CPU存储数据操作的最小单位是一个字节(Byte),其内部的比特序对程序员并不可见,类似于一个盲盒。假设存在某一个字节,其中存放的是0x12,程序通过指针访问到该字节,不论该字节是LSB 0还是MSB 0,得到的返回值都是0x12[对程序员来说,该字节内部的比特序不可见];
  3. 串口是LSB优先,I2C、1553B是MSB优先;

4. 常见题

  1. 写一段代码判断机器时大端模式还是小端模式
    方法一:利用union联合体(如果不了解union的同志,建议先去看下union的知识点,毕竟这玩意不常用)
int main()
{
	union NU
	{
		short a;
		char b;
	}num;
	num.a = 0x1234;
	if(num.b == 0x34)
		printf("little-endian\n");
	else if(num.b == 0x12)
		printf("big-endian\n");
}
//利用union所有的数据成员具有相同的起始地址这一属性来判断大小端

方法二:指针法,即通过强制类型转换,测试大小端

#define	 little_endian	0;
#define  big_endian		1;
int main()
{
	short a = 0x1234;
	char  b = *(char *)&a;	
	if(b == 0x34)
		return 0;
	else if (b == 0x12)
		return 1;
}
//将short强转为char,通过判断起始存储,即取b等于a的低地址部分
  1. 大小端转换
    位操作方法
typedef unsigned int u_int32;
#define Byte_Reverse(x)		(									  \
							 (((u_int32)(x) & 0xff000000) >> 24) |\
							 (((u_int32)(x) & 0x00ff0000) >> 8)  |\
							 (((u_int32)(x) & 0x0000ff00) << 8)  |\
							 (((u_int32)(x) & 0x000000ff) << 24)  \
							)
int main()
{
	printf("%#x\n", Byte_Reverse(0x12345678));
}							 
//输出结果为:0x78563412

点个关注再走?

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值