大小端、字节序问题

大小端、字节序问题

大小端解析
端模式出自Jonathan Swift书写的《格列佛游记》一书,这本书根据将鸡蛋敲开的方法不同将所有的人分为两类,从圆头开始将鸡蛋敲开的人被归为Big Endian,从尖头开始将鸡蛋敲开的人被归为Littile Endian。小人国的内战就源于吃鸡蛋时是究竟从大头(Big-Endian)敲开还是从小头(Little-Endian)敲开。
在计算机业Big Endian和Little Endian也几乎引起一场战争。在计算机业界,Endian表示数据在存储器中的存放顺序。
大端:高位存在低地址,低位存在高地址;
      小端:高位存在高地址,低位存在低地址;(intel的x86,ARM普遍都是属于小端)

举个例子,从内存地址0x0000开始有以下数据
        0x0000    0x12
        0x0001    0x34
        0x0002    0xab
        0x0003    0xcd
如果我们去读取一个地址为0x0000的四个字节变量:
        若字节序为big-endian,则读出结果为0x1234abcd;
        若字节序位little-endian,则读出结果为0xcdab3412.

如果我们将0x1234abcd写入到以0x0000开始的内存中,则结果为:
                  big-endian      little-endian
        0x0000          0x12                  0xcd
        0x0001          0x23                  0xab
        0x0002          0xab                  0x34
        0x0003          0xcd                  0x12

判断大小端的函数
int checkCPUendian()//返回1,为小端;反之,为大端;  
{  
    union  
    {  
        unsigned int  a;  
        unsigned char b;  
    }c;  
    c.a = 1;  
    return 1 == c.b;  
}  


网络字节序
我们知道网络上的数据流是字节流,对于一个多字节数值,在进行网络传输的时候,先传递哪个字节?也就是说,当接收端收到第一个字节的时候,它是将这个字节作为高位还是低位来处理呢?
数据在网络传输的过程中,也就是说: 从主机A到主机B进行通信,
A的固有数据存储---->标准化---->转化成B的固有格式
注: 标准化就是网络字节序(也是大端字节序)

网络字节序定义:收到的第一个字节被当作高位看待,这就要求发送端发送的第一个字节应当是高位。而在发送端发送数据时,发送的第一个字节是该数字在内存中起始地址对应的字节。可见多字节数值在发送前,在内存中数值应该以大端法存放。


在实际的工程应用中,无论主机a和b的字节序,是否一样,为了程序的可移植性和兼容性,都建议数据发送主机进行主机字节序到网络字节序的转换,数据接收机进行网络字节序到主机字节序的转换。在c++中,有4个函数可以实现主机字节序到网络字节序的相互转换,如下:
htons: 把unsigned short类型从主机序转换到网络序
   htonl: 把unsigned long类型从主机序转换到网络序
   ntohs: 把unsigned short类型从网络序转换到主机序
   ntohl: 把unsigned long类型从网络序转换到主机序

字节序的转换
1. linux + C++ 实现主机字节序和网络字节序的转换代码
#include <arpa/inet.h> //1.包含arpa/inet.h
#include <stdio.h>
int main()
{
int port=6000;
int netPort=htonl(port);
printf("netPort=%d\n",netPort);
printf("hostPort=%d\n",ntohl(netPort));
return 1;
}

output:
  netPort=1880555520
  hostPort=6000

2. Windows + C++ 实现主机字节序和网络字节序的转换代码
#include <stdio.h>
#include <Winsock2.h> //1.包含<Winsock2.h>,
#pragma comment( lib, "ws2_32.lib") //2.引入ws2_32.lib库
void main()
{
int port=6000;
int netPort=htonl(port);
printf("netPort=%d\n",netPort);
printf("hostPort=%d\n",ntohl(netPort));
}

output:
  netPort=1880555520
  hostPort=6000
### 嵌入式系统中大小端字节序的概念及应用 #### 大小端字节序定义 大端字节序(Big Endian)和小端字节序(Little Endian)是描述多字节数据在计算机内存中存储顺的方式。对于一个多字节的数据,例如一个32位整数,在大端模式下,最高有效字节被存放在最低地址处;而在小端模式下,则相反,最低有效字节被存放在最低地址处[^2]。 #### 区别 两者的根本区别在于它们如何解释多字节对象的存储位置: - **大端字节序**:高位字节优先存储于低地址。 - **小端字节序**:低位字节优先存储于低地址。 这种差异直接影响到跨平台间的数据交换以及硬件设计的选择。当不同架构之间进行通信时,如果不统一字节序可能会导致错误解析接收到的信息[^1]。 #### 应用场景 在嵌入式领域内,字节序的应用非常广泛,尤其是在以下几个方面: - 数据传输过程中确保接收方能够按照发送方预期的方式来解读消息内容; - 文件格式规定特定编码方式以便兼容多种设备读取; - 设备驱动程编写需考虑目标处理器支持何种类型的字节序列从而正确操作外设寄存器等资源。 #### 转换方法 实现大小端之间的相互转变可以通过软件层面完成也可以借助专门指令集加速处理速度。以下是几种常见的做法: ##### 使用标准库函数 C/C++语言提供了几个用于改变主机默认字节次网络通用形式(通常是big-endian)的标准APIs, 如htonl(), htons() ,ntohl(), ntohs(). 这些功能可以方便快捷地解决因体系结构引起的问题. ```c #include <arpa/inet.h> uint32_t host_to_network_long(uint32_t hostlong){ return htonl(hostlong); } ``` ##### 手动重组字节 另一种更为灵活但可能效率较低的方法就是手动调整每一个组成部分的位置关系直到达到期望的结果为止。这种方法尤其适用于那些没有现成工具可用的情况或者是针对特殊需求定制解决方案的时候[^3]。 ```python import struct def float_endian_swap(f): packed = struct.pack('f', f) swapped_bytes = bytearray(packed)[::-1] result = struct.unpack('f', bytes(swapped_bytes))[0] return result ``` 上述Python代码片段展示了如何利用`struct`模块先将浮点数值打包成二进制表示然后再颠倒其内部组成单元最终得到反转后的版本。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值