程序员求职经验分享与学习资料整理平台

网站首页 > 文章精选 正文

嵌入式C语言中针对大小端的处理(嵌入式大小端模式)

balukai 2025-07-21 12:39:09 文章精选 11 ℃

我在上一个专题中,讲联合体的应用时,有朋友提到了关于大小端的问题。我感觉我在回复里也没有讲得太清楚,我就专门再开一个专题来探讨一下。同时在这里,也欢迎大家一起来讨论,也欢迎大家关注我的头条号。

首先我们先来搞清楚一个问题,

为什么会有大小端的区别?

对于一个处理器来讲,一般是一个字节(byte)的存储空间对应一个唯一的地址。8位的处理器不存在大小端的问题,这个问题主要针对的是16位和32位的处理器。以32位处理器为例,我们说的32位,实际就是指的处理器的地址总线是32位的。也就是说,在32位处理器的存储空间里,每一个字节对应一个32位地址,当然这个地址是唯一的。那么我们在处理一个字(word)的时候,也就是4个字节(byte),要把这4个字节分别放入4个连续的地址中,一般也就是两种方式。一种低位在前,byte0放在低地址中,再从byte1到byte3依次按顺序往后放;另一种高位在前,byte3放在低地址中,再从byte2到byte0依次按顺序往后放。前面这一种方式,就叫做小端模式;后面这一种方式,就叫做大端模式。

上图就是数值0x1,在小端模式和大端模式下的不同存储方法。

大小端模式取决于芯片内核

由此,我们可以看出大小端不同的模式,完全取决于芯片的内核。各个芯片设计公司,对此有各自自己的玩法。这也不能完全怪人家,为什么不统一标准。现实中,有好多设计有时候是设计者刻意为之,后者往往为了区别于前者的设计,而采取另外一条路,实际上是殊途同归。但是这样做却可以规避一个叫做“专利”的东西。

针对大小端数据结构的定义

为了程序能够跨平台使用,我们也经常定义这样的数据结构,

typedef union
{
  t_uint32 Word;

  struct 
  {
    #if ENDIAN_MODE == BIG_END
      t_uint8 Byte3;
      t_uint8 Byte2;
      t_uint8 Byte1;
      t_uint8 Byte0;    
    #else
      t_uint8 Byte0;
      t_uint8 Byte1;
      t_uint8 Byte2;
      t_uint8 Byte3;
    #endif    
  }Byte;
  
}un_uint32;

如果是大端模式,你可以将ENDIAN_MODE定义成BIG_END,否则你就定义成LITTLE_END,你可以选择默认小端模式。现在基本上是arm内核大行其道,arm内核既支持小端模式又支持大端模式,但是也是默认小端模式。这也算是回答了网友提出来的问题。

与大小端问题类似的,还有LSB和MSB的问题,在这里也一起讨论一下。

数据通讯中LSB和MSB

在数据通讯中,一般数据流有两种通讯方式:LSB和MSB。LSB,低位在前,也就是低位先发;MSB,高位在前,也就是高位先发。我看有些文章里,把这个问题和大小端问题,混为一谈,我个人其实不太认同。一个是针对数据通信,一个是针对数据存储,虽然都是在定义先后顺序。你要是非要说数据存储还不是由数据传输决定的,先传输谁就先存储谁,那也算是这两个问题在一定程度上的统一。

但是, 我还是觉得把这两个问题分开来对待还是比较好。如果硬要把这两个问题都归类到一起,那也是在完全理解各自问题的基础之上。

最近发表
标签列表