大端or小端

一、字节序定义

字节序,顾名思义字节的顺序,再多说两句就是大于一个字节类型的数据在内存中的存放顺序(一个字节的数据当然就无需谈顺序的问题了)。

其实大部分人在实际的开发中都很少会直接和字节序打交道。唯有在跨平台以及网络程序中字节序才是一个应该被考虑的问题。

在所有的介绍字节序的文章中都会提到字节序分为两类:Big-Endian和Little-Endian。引用标准的Big-Endian和Little-Endian的定义如下:
a) Little-Endian就是低位字节排放在内存的低地址端,高位字节排放在内存的高地址端。
b) Big-Endian就是高位字节排放在内存的低地址端,低位字节排放在内存的高地址端。
c) 网络字节序:4个字节的32 bit值以下面的次序传输:首先是0~7bit,其次8~15bit,然后16~23bit,最后是24~31bit。这种传输次序称作大端字节序。由于TCP/IP首部中所有的二进制整数在网络中传输时都要求以这种次序,因此它又称作网络字节序。比如,以太网头部中2字节的“以太网帧类型”,表示后面数据的类型。对于ARP请求或应答的以太网帧类型来说,在网络传输时,发送的顺序是0x08,0x06。在内存中的映象如下图所示:
栈底 (高地址)
---------------
0x06 -- 低位 
0x08 -- 高位
---------------
栈顶 (低地址)
该字段的值为0x0806。按照大端方式存放在内存中。

二、高/低地址与高低字节

首先我们要知道我们C程序映像中内存的空间布局情况:在《C专家编程》中或者《Unix环境高级编程》中有关于内存空间布局情况的说明,大致如下图:
----------------------- 最高内存地址 0xffffffff
 | 栈底
 .
 .              栈
 .
  栈顶
-----------------------
 |
 |
/|/

NULL (空洞)

/|/
 |
 |
-----------------------
                堆
-----------------------
未初始化的数据
----------------(统称数据段)
初始化的数据
-----------------------
正文段(代码段)
----------------------- 最低内存地址 0x00000000

以上图为例如果我们在栈上分配一个unsigned char buf[4],那么这个数组变量在栈上是如何布局的呢[注1]?看下图:
栈底 (高地址)
----------
buf[3]
buf[2]
buf[1]
buf[0]
----------
栈顶 (低地址)

现在我们弄清了高低地址,接着来弄清高/低字节,如果我们有一个32位无符号整型0x12345678(呵呵,恰好是把上面的那4个字节buf看成一个整型),那么高位是什么,低位又是什么呢?其实很简单。在十进制中我们都说靠左边的是高位,靠右边的是低位,在其他进制也是如此。就拿0x12345678来说,从高位到低位的字节依次是0x12、0x34、0x56和0x78。

高低地址和高低字节都弄清了。我们再来回顾一下Big-Endian和Little-Endian的定义,并用图示说明两种字节序:
以unsigned int value = 0x12345678为例,分别看看在两种字节序下其存储情况,我们可以用unsigned char buf[4]来表示value:
Big-Endian: 低地址存放高位,如下图:
栈底 (高地址)
---------------
buf[3] (0x78) -- 低位
buf[2] (0x56)
buf[1] (0x34)
buf[0] (0x12) -- 高位
---------------
栈顶 (低地址)

Little-Endian: 低地址存放低位,如下图:
栈底 (高地址)
---------------
buf[3] (0x12) -- 高位
buf[2] (0x34)
buf[1] (0x56)
buf[0] (0x78) -- 低位
---------------
栈顶 (低地址)

在现有的平台上Intel的X86采用的是Little-Endian,而像Sun的SPARC采用的就是Big-Endian。

三、例子

嵌入式系统开发者应该对Little-endian和Big-endian模式非常了解。采用Little-endian模式的CPU对操作数的存放方式是从低字节到高字节,而Big-endian模式对操作数的存放方式是从高字节到低字节。

例如,16bit宽的数0x1234在Little-endian模式CPU内存中的存放方式(假设从地址0x4000开始存放)为:

内存地址  存放内容
 0x4001    0x12
 0x4000    0x34

而在Big-endian模式CPU内存中的存放方式则为:

内存地址  存放内容
 0x4001    0x34
 0x4000    0x12
 
32bit宽的数0x12345678在Little-endian模式CPU内存中的存放方式(假设从地址0x4000开始存放)为:

内存地址  存放内容
 0x4003     0x12
 0x4002     0x34
 0x4001     0x56
 0x4000     0x78
 
而在Big-endian模式CPU内存中的存放方式则为:

内存地址  存放内容
 0x4003     0x78
 0x4002     0x56
 0x4001     0x34
 0x4000     0x12

 以上是从别人那copy的,intel处理器用的是小端的,mac,ibm用的是大端

网络字节序也是大端,java貌似也是大端

### 大端模式与小模式在UDS汽车网络通信协议中的实现 #### UDS协议概述 UDS (Unified Diagnostic Services) 是一种用于车辆内部电子控制单元(ECU)间诊断通讯的标准。此标准定义了一系列的服务来支持ECUs间的交互,包括但不限于读取数据、执行测试和编程等操作。 #### 数据表示方式的选择 对于采用何种字节序(即大端还是小),这取决于具体的应用场景以及硬件平台的设计选择。通常情况下,在汽车行业里,不同的制造商可能会有不同的偏好;然而,为了确保互操作性和标准化,许多时候会倾向于使用特定的一种字节顺序作为默认选项[^1]。 #### 实现细节 - **小模式**:按照小规则编码的数据会被先发送最低有效字节(LSB),这意味着如果有一个多字节数值0x12345678,则在网络上传输时其形式将是`78 56 34 12`。这种做法常见于某些基于ARM架构或其他微控制器的系统中。 - **大端模式**:相反地,在大端模式下,最高有效字节(MSB)将首先被传送出去,因此上述例子将以`12 34 56 78`的形式出现在网络流量里面。这种方式更接近人类直觉上的数位排列习惯,并且广泛应用于诸如MIPS之类的RISC处理器家族当中[^2]。 #### 服务调用的影响 考虑到DCM(Diagnostic Communication Manager)模块所提供的通用API是为了让诊断工具能够方便地访问并管理各种类型的诊断请求和服务响应,所以在涉及到跨设备或不同品牌车型之间的兼容性问题时,保持一致性的字节序就显得尤为重要了。当一个诊断仪向某个ECU发起查询命令时,双方都应当清楚对方使用的字节序列化方法是什么样的,这样才能保证所交换的信息不会因为误解而导致错误解析。 ```python def send_uds_request(data, endian='little'): """ 发送UDS请求前根据指定的字节序调整数据 :param data: 待发送的数据列表/元组 :type data: list or tuple of int :param endian: 字节序 ('big' 或 'little') :type endian: str :return: 调整后的字节串 :rtype: bytes """ if endian not in ['big', 'little']: raise ValueError("Invalid endian type") byte_data = b''.join([d.to_bytes((len(hex(d)) - 2) // 2 + ((len(hex(d)) - 2) % 2), byteorder=endian) for d in data]) return byte_data ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值