大小端字节序(Big Endian和Little Endian)

2023-05-16

那么何为字节序(Endia)呢?
Big Endian是指低地址存放最高有效字节(MSB),而Little Endian则是低地址存放最低有效字节(LSB)。

大端模式

所谓的大端模式(Big-endian),是指数据的高字节,保存在内存的低地址中,而数据的低字节,保存在内存的高地址中,这样的存储模式有点儿类似于把数据当作字符串顺序处理:地址由小向大增加,而数据从高位往低位放;

例子:


0000430: e684 6c4e 0100 1800 53ef 0100 0100 0000

0000440: b484 6c4e 004e ed00 0000 0000 0100 0000

在大端模式下,前32位应该这样读: e6 84 6c 4e ( 假设int占4个字节)

记忆方法: 地址的增长顺序与值的增长顺序相反

小端模式

所谓的小端模式(Little-endian),是指数据的高字节保存在内存的高地址中,而数据的低字节保存在内存的低地址中,这种存储模式将地址的高低和数据位权有效地结合起来,高地址部分权值高,低地址部分权值低,和我们的逻辑方法一致。

例子:

0000430: e684 6c4e 0100 1800 53ef 0100 0100 0000

0000440: b484 6c4e 004e ed00 0000 0000 0100 0000

在小端模式下,前32位应该这样读: 4e 6c 84 e6( 假设int占4个字节)

记忆方法: 地址的增长顺序与值的增长顺序相同

有图有真相,举个例子,数字 0x12345678 在两种不同字节序CPU中的存储顺序如下图

在这里插入图片描述

为什么会有这样的情况呢?
这是因为在计算机系统中,我们是以字节为单位的,每个地址单元都对应着一个字节,一个字节为8bit。但是在C语言中除了8bit的char之外,还有16bit的short型,32bit的long型(要看具体的编译器),另外,对于位数大于8位的处理器,例如16位或者32位的处理器,由于寄存器宽度大于一个字节,那么必然存在着一个如果将多个字节安排的问题。因此就导致了大端存储模式和小端存储模式。例如一个16bit的short型x,在内存中的地址为0x0010,x的值为0x1122,那么0x11为高字节,0x22为低字节。对于大端模式,就将0x11放在低地址中,即0x0010中,0x22放在高地址中,即0x0011中。小端模式,刚好相反。我们常用的X86结构是小端模式,而KEIL C51则为大端模式。很多的ARM,DSP都为小端模式。有些ARM处理器还可以由硬件来选择是大端模式还是小端模式。

Motorola的PowerPC系列CPU采用Big Endian方式存储数据。
Intel的x86系列CPU采用Little Endian方式存储数据。
ARM既可以工作在大端模式,也可以工作在小端模式。
再来说说,一些我所收集到的情况吧。
Windos(x86,x64)和Linux(x86,x64)都是Little Endian操作系统
在ARM上,我见到的都是用Little Endian方式存储数据。
C/C++语言编写的程序里数据存储顺序是跟编译平台所在的CPU相关的。
JAVA编写的程序则唯一采用Big Endian方式来存储数据。
所有网络协议也都是采用Big Endian的方式来传输数据的。所以有时我们也会把Big Endian方式称之为网络字节序。

为什么要注意字节序的问题呢?
你可能这么问。当然,如果你写的程序只在单机环境下面运行,并且不和别人的程序打交道,那么你完全可以忽略字节序的存在。但是,如果你的程序要跟别人的程序产生交互呢?尤其是当你把你在微机上运算的结果运用到计算机群上去的话。在这里我想说说两种语言。C/C++语言编写的程序里数据存储顺序是跟编译平台所在的CPU相关的,而JAVA编写的程序则唯一采用big endian方式来存储数据。试想,如果你用C/C++语言在x86平台下编写的程序跟别人的JAVA程序互通时会产生什么结果?就拿上面的 0x12345678来说,你的程序传递给别人的一个数据,将指向0x12345678的指针传给了JAVA程序,由于JAVA采取big endian方式存储数据,很自然的它会将你的数据翻译为0x78563412。什么?竟然变成另外一个数字了?是的,就是这种后果。因此,在你的C程序传给JAVA程序之前有必要进行字节序的转换工作。

网络字节序
一、在进行网络通信时是否需要进行字节序转换?
相同字节序的平台在进行网络通信时可以不进行字节序转换,但是跨平台进行网络数据通信时必须进行字节序转换。

原因如下:网络协议规定接收到得第一个字节是高字节,存放到低地址,所以发送时会首先去低地址取数据的高字节。小端模式的多字节数据在存放时,低地址存放的是低字节,而被发送方网络协议函数发送时会首先去低地址取数据(想要取高字节,真正取得是低字节),接收方网络协议函数接收时会将接收到的第一个字节存放到低地址(想要接收高字节,真正接收的是低字节),所以最后双方都正确的收发了数据。而相同平台进行通信时,如果双方都进行转换最后虽然能够正确收发数据,但是所做的转换是没有意义的,造成资源的浪费。而不同平台进行通信时必须进行转换,不转换会造成错误的收发数据,字节序转换函数会根据当前平台的存储模式做出相应正确的转换,如果当前平台是大端,则直接返回不进行转换,如果当前平台是小端,会将接收到得网络字节序进行转换。

二、网络字节序
​ 网络上传输的数据都是字节流,对于一个多字节数值,在进行网络传输的时候,先传递哪个字节?也就是说,当接收端收到第一个字节的时候,它将这个字节作为高位字节还是低位字节处理,是一个比较有意义的问题; UDP/TCP/IP协议规定:把接收到的第一个字节当作高位字节看待,这就要求发送端发送的第一个字节是高位字节;而在发送端发送数据时,发送的第一个字节是该数值在内存中的起始地址处对应的那个字节,也就是说,该数值在内存中的起始地址处对应的那个字节就是要发送的第一个高位字节(即:高位字节存放在低地址处);由此可见,多字节数值在发送之前,在内存中因该是以大端法存放的; 所以说,网络字节序是大端字节序; 比如,我们经过网络发送整型数值0x12345678时,在80X86平台中,它是以小端发存放的,在发送之前需要使用系统提供的字节序转换函数htonl()将其转换成大端法存放的数值;

c# 大端转换
c#在windows平台上是小端字节序(Windos(x86,x64)和Linux(x86,x64)都是Little Endian操作系统,不止是c#)。网络发送字节流是按大端序发送,也就是从左到右发送,和c#的小端序相反,造成网关不能正常识别协议。所以需要转换

大小端转换

int x = 439041118;  // 十六进制为 1A2B3C5E

string s = null;

byte[] b = BitConverter.GetBytes( x );

s = BitConverter.ToString( b ); // 小端模式
Console.WriteLine( s ); // 小端输出 为 5E-3C-2B-1A

Array.Reverse( b ); // 反转

s = BitConverter.ToString( b ); // 大端模式
Console.WriteLine( "{0:x}", s ); // 大端输出 为 1A-2B-3C-5E

Console.ReadKey();

C# 判断数据在此计算机结构中存储时的字节顺序(“Endian”性质),即大端还是小端

int data = 439041118; // 十六进制为 1A2B3C5E
byte[] bData = BitConverter.GetBytes( data );
            
if (BitConverter.IsLittleEndian) // 若为 小端模式
{
   Array.Reverse( bData ); // 转换为 大端模式               
}
string s = BitConverter.ToString( bData );

Console.WriteLine(s);

Console.ReadKey();

一些封装

//翻转byte数组
public static void ReverseBytes(byte[] bytes)
{
    byte tmp;
    int len = bytes.Length;

    for (int i = 0; i < len / 2; i++ )
    {
        tmp = bytes[len - 1 - i];
        bytes[len - 1 - i] = bytes[i];
        bytes[i] = tmp;
    }
}

//规定转换起始位置和长度
 public static void ReverseBytes(byte[] bytes, int start, int len)
 {
     int end = start + len - 1;
     byte tmp;
     int i = 0;
     for (int index = start; index < start + len/2; index++,i++)
     {
         tmp = bytes[end - i];
         bytes[end - i] = bytes[index];
         bytes[index] = tmp;
     }
 }

// 翻转字节顺序 (16-bit)
public static UInt16 ReverseBytes(UInt16 value)
{
  return (UInt16)((value & 0xFFU) << 8 | (value & 0xFF00U) >> 8);
}


// 翻转字节顺序 (32-bit)
public static UInt32 ReverseBytes(UInt32 value)
{
  return (value & 0x000000FFU) << 24 | (value & 0x0000FF00U) << 8 |
         (value & 0x00FF0000U) >> 8 | (value & 0xFF000000U) >> 24;
}


// 翻转字节顺序 (64-bit)
public static UInt64 ReverseBytes(UInt64 value)
{
  return (value & 0x00000000000000FFUL) << 56 | (value & 0x000000000000FF00UL) << 40 |
         (value & 0x0000000000FF0000UL) << 24 | (value & 0x00000000FF000000UL) << 8 |
         (value & 0x000000FF00000000UL) >> 8 | (value & 0x0000FF0000000000UL) >> 24 |
         (value & 0x00FF000000000000UL) >> 40 | (value & 0xFF00000000000000UL) >> 56;
}
另外c#直接提供了网络字节序转换方法。

System.Net.IPAddress.HostToNetworkOrder(本机到网络转换)

System.Net.IPAddress.NetworkToHostOrder(网络字节转成本机)

推荐使用这种方法,简单有效。

short x = 6;
short b = System.Net.IPAddress.HostToNetworkOrder(x); //把x转成相应的大端字节数
byte[] bb = System.BitConverter.GetBytes(b);//这样直接取到的就是大端字节序字节数组。
对于字符串型:
使用 System.Text.Encoding.Default.GetBytes();直接取字串对应字节数组。

不知道为什么这个方法取到的直接就是大端字节数组。不用转换。

后来查了一下,关于字串的字节序问题,因为gbk和utf-8都是以单个字节表示数字的,所以不存在字节序问题,在多个不同系统架构都用。对于utf-16,则是以双字节表示一个整数,所以为会有字节序问题,分大小端unicode。

System.Text.Encoding.Default.GetBytes();在我的简体中文系统上是以gb2312的编码,也就是单个字来进行编码的,所以也不会有字节序问题。

补充:“对于任何字符编码,编码单元的顺序是由编码方案指定的,与endian无关。例如GBK的编码单元是字节,用两个字节表示一个汉字。这两个字节的顺序是固定的,不受CPU字节序的影响。UTF-16的编码单元是word(双字节),word之间的顺序是编码方案指定的,word内部的字节排列才会受到endian的影响。”,

所以utf-8也没有字节序的问题。字节序问题之存在于需要使用两个字节以上来表示整数。而UTF-8只是一串字节流,不存在字节序问题,不过将这些字节流翻译成Unicode比其他的传输方式复杂。以字节为单位编码的,无论一个汉字是多少个字节,都无字节序问题。

你注意,字节序问题不是指多个字节传输的先后,这个是固定的无异议的。而是指一个多字节编码在机器中的表示方式问题。
char str[] = “abaksdkakskasklasflk”;

这个无字节序问题。但
int str[] = {0x11223344, 2, 3 }

就有字节序问题了。因为str[0]同样数值不同机器中表示不同。

而剩下的, 就是字符编码内部的字节序了。比如UTF-16是用两个字节表示一个字符,但是这两个字节内部如何排序,系统并不知道,所以必须指定字节序。但是UTF-8由于几个字节表示并不相同,一定要从那个表示长度的字节开始读,相当于一开始就知道该从哪里是队头队尾,所以不存在字节序问题。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

大小端字节序(Big Endian和Little Endian) 的相关文章

  • 音响发烧友---HiFi音频功放

    最近一直想做个开源的电子项目 xff0c 思考许久还是选择做个HiFi音频功放 作为一个音响发烧友 xff0c 带大家DIY一台属于自己的功放 聆听一下 xff0c 纯正的音乐之美 首选需要了解一下功放的类型 xff1a 纯甲类功率放大器乙
  • Altium Designer20常用使用快捷键

    一 AD20常用快捷键 PCB布线常使用 xff1a ctrl 43 m 测量长度 Q 单位切换 shift 43 ctrl 43 r 取消显示标注 shift 43 S 显示层切换 ctrl 43 右击 高亮显示一条线 ctrl 43 D
  • Altium Designer20 交叉选择模式

    在使用Altium Designer进行PCB布局时 xff0c 首先我们需要将原理图元器件更新到PCB中 xff0c 所有的元件封装都会汇集到PCB中 xff0c 但并没有根据电路模块进行分类聚集 xff1b 我们可以使用AD的交叉选择模
  • Altium Designer20 批量修改元件丝印大小和位置

    在进行PCB布线时 xff0c 我们经常需要调整元件丝印的大小和位置 有了丝印才能在PCB焊接和调试板子的时候得心应手 xff0c 下面介绍一种便捷的方法 xff0c 来实现批量修改元件丝印和位置 1 修改元件丝印大小 xff08 1 xf
  • 图像重叠区域

    http www cnblogs com dwdxdy archive 2013 08 02 3232331 html
  • bat批处理---实现输入指定拷贝文件

    在windows平台下 xff0c 平常的给芯片下载程序过程中 xff0c 经常遇到需要在多个文件夹下面拷贝bin文件的情况 xff0c 为了实现能够通过输入参数 xff0c 来选择需要拷贝的问下 xff0c 写了一个 bat批处理文件 只
  • Altium Designer20 PCB规则设置

    我们在进行PCB布线之前 xff0c 需要对PCB布线进行规则设置 xff0c 如果大家只是DIY爱好者 xff0c 那我们将设置价格最经济的PCB规则 xff0c 我们可以以捷配官网的PCB工艺信息作为参考 xff1b 下面我将介绍常用的
  • 入门到放弃之 NVMe-MI --- 协议简介

    在学习NVMe MI协议之前 xff0c 感觉协议是如此的枯燥 xff0c 通过短时间的阅读Spec发现协议规范定义的精妙绝伦 xff1b 协议中各种细节处理的相当到位 xff0c 最有趣的是消息服务模型的状态机设计 xff0c 希望大家一
  • NVMe-MI --- Message Transport(消息传输)

    3 消息传输 该规范定义了一个支持多种消息传输的接口 消息格式与带外机制和带内隧道机制相同 3 1 NVMe MI消息 NVMe MI消息在带外机制和带内隧道机制中都有使用 NVMe MI消息的格式如图17和图18所示 在带外机制中 xff
  • NVMe-MI --- Message Servicing Model(消息服务模型)

    4 消息服务模型 4 1 NVMe MI 消息 图23展示了NVMe MI消息的分类 NVMe MI消息的两个主要类别是请求消息和响应消息 当使用带外机制时 xff0c 请求消息由管理控制器发送到管理端点 在使用带内隧道机制时 xff0c
  • NVMe-MI --- Management Interface Command Set

    Management Interface Command Set 命令集定义了当NMIMT值被设置为NVMe MI命令时 xff0c 请求者可以提交的命令信息 管理接口命令集同时适用于带外机制和带内隧道机制 NVMe MI消息结构以及所有N
  • PCIe总线引脚定义

    然后看一下PCI E的接口定义 这就是显卡插口前面的那段短的金手指 xff0c 就是这段 xff1a 这一段负责供电 SMBus和感知设备是否插上 xff0c 对于数据的传输作用不大 xff0c 所以不用深究 用浅绿色标出来的是检测插槽上设
  • Mbus新增主动报警功能,简单问题的波折路程。

    由于用到了主动报警上传功能 一个简单的if判断 xff0c 便实现了判断与上传功能 脱机测试 xff0c 上流量台测试 xff0c 都正常 以为这件事便了了 结果到了现场却给暴出了问题 xff0c 没法收到报警 于是 xff0c 一对一的现
  • 相机IMU联合标定

    单目相机内参标定 xff1a xff08 焦距 xff0c 光心 https blog csdn net qq 42399848 article details 89298212 ops request misc 61 257B 2522r
  • Hough变换理解

    reference http blog csdn net app 12062011 article details 11307053 一 简单介绍 Hough变换是图像处理中从图像识别几何形状的基本方法之一 xff0c 霍夫变换寻找直线和圆
  • 1.常见8种排序算法分析笔记之-空间O(1)三种(冒泡、选择、插入)

    文章目录 空间复杂度为O 1 的三种排序法一 冒泡排序法1 代码实现思想2 复杂度分析3 代码实现4 代码测试 二 选择排序法1 代码实现思想2 复杂度分析3 代码实现4 代码测试 三 插入排序法1 代码实现思想2 复杂度分析3 代码实现4
  • 2.常见8种排序算法分析笔记之-时间O(NlogN)三种(归并、快排、堆排序)

    文章目录 时间复杂度为 O N l o g
  • 3.常见8种排序算法分析笔记之-时间性能突破O(n^2)的原地排序法-希尔排序法

    文章目录 时间性能突破 O n 2
  • 项目1在线交流平台-6.Elasticsearch分布式搜索引擎-2.Spring整合Elasticsearch测试

    文章目录 一 导入依赖和配置1 导入依赖2 配置连接3 解决启动Netty冲突 二 SpringData集成ES测试1 配置实体类与ES索引字段相对应 96 64 Document indexName 61 34 discusspost 3
  • 项目1在线交流平台-6.Elasticsearch分布式搜索引擎-3.ES结合Kafka应用-开发社区搜索功能

    文章目录 功能需求一 Service层处理操作ES服务器的数据二 Controller层处理帖子添加和评论事件请求1 添加帖子时 触发事件 发布消息2 添加评论时 触发发帖事件 发布消息 三 kafka消费者订阅消息并提交到ES服务器四 处

随机推荐

  • 项目1在线交流平台-7.构建安全高效的企业服务-2.使用Security自定义社区网页认证与授权

    文章目录 功能需求一 废弃登录检查的拦截器二 授权配置1 导包2 Security配置2 1 96 WebSecurity 96 2 2 96 HttpSecurity 96 96 http authorizeRequests 96 96
  • 项目1在线交流平台-7.构建安全高效的企业服务-3. Security整合Kafka,ES,Thymeleaf实例-对帖子置顶、加精、删除

    文章目录 功能需求一 置顶 加精 删除帖子功能的实现1 dao层处理数据接口定义sal语句定义 2 service层业务处理3 Controller层处理按钮事件异步请求异步请求及kafka发送消息删除帖子 消费消息 4 模板页面和js文件
  • JVM虚拟机学习笔记之-5. 字节码执行引擎

    文章目录 1 字节码执行引擎工作概览2 栈帧2 1 栈帧概述和概念结构2 2 局部变量表2 2 1 局部变量表分配规则2 2 2 局部变量表回收机制 2 3 操作数栈2 4 动态连接2 5 方法返回地址2 6 方法调用 3 分派3 1 静态
  • leetcode刷题记录总结-7.递归回溯算法(进行中)

    文章目录 零 回溯算法理论总览什么是回溯法回溯法的效率回溯法解决的问题如何理解回溯法回溯法模板 一 组合问题 77 组合 https leetcode cn problems combinations 题解递归实现组合型枚举 xff1a 每
  • Linux服务器开发-1. Linux系统编程复习

    文章目录 1 GCC1 1 gcc概念1 2 编程语言的发展1 3 gcc工作流程1 4 常见指令选项预处理 xff1a 指令 E xff1a 编译 xff1a 指令 S汇编 xff1a 指令 c链接 xff1a 指令 o指定宏 xff1a
  • 8皇后问题

    span class hljs keyword bool span check span class hljs stl container span class hljs built in vector span lt span class
  • Linux服务器开发-2. Linux多进程开发

    文章目录 1 进程概述1 1 程序概览1 2 进程概念1 3 单道 多道程序设计1 4 时间片1 5 并行与并发1 6 进程控制块 xff08 PCB xff09 2 进程的状态转换2 1 进程的状态2 2 进程相关命令查看进程实时显示进程
  • CMakeLists.txt 构建 Qt工程

    源码路径下包括 xff1a main cpp test cpp test h test ui test qrc cmake minimum required VERSION 3 1 0 project test SET CMAKE INCL
  • 【技术】RTK定位是什么?危化安全生产必看

    RTK定位技术是建立在流动站与基准站误差非常类似的基础上的 xff0c 它利用GPS载波相位观测值进行实时动态定位 RTK定位广受危化行业欢迎 xff0c 成为危化安全生产的热门技术选项 伴随着经济的高速发展 xff0c 信息技术取得了进一
  • GPS/RTK高精度定位系统有什么优势?

    GPS RTK高精度定位系统能提供厘米级 毫米级高精度位置服务 xff0c 逐渐成为智能社会高精度定位的趋势和理想选择 GPS RTK高精度定位系统的出现是信息化时代发展的产物 从移动互联到物联网 xff0c 位置是一个基础的不可或缺的信息
  • 【分享】高精度RTK定位解决方案

    高精度RTK定位系统采用高精度定位标签 xff0c 通过计算机技术 地理信息技术 移动定位技术 通信技术 网络技术 xff0c 为生产现场作业人员配发定位终端 xff0c 实时追踪其位置信息进行相关管控 xff0c 为其活动提供安全技术保障
  • 【分享】5G+北斗RTK高精度人员定位解决方案

    5G 43 北斗RTK高精度定位系统旨在通过5G网络实时提供亚米级 厘米级 毫米级高精度定位服务 xff0c 构建全天候 全天时 全地理的精准时空服务体系 伴随着信息技术日新月异的发展 xff0c 各类 智慧 顺势而出 xff0c 智慧城市
  • 5G+北斗RTK定位:高精度定位技术发展更进一步

    5G 43 北斗RTK定位采用5G定位与北斗RTK定位技术 xff0c 在信号 信息 设施 应用等层面深度融合 xff0c 5G自身可实现亚米级的定位能力与北斗形成信号覆盖互补 xff0c 实现从室内到室外无缝隙衔接与定位 5G通信技术的到
  • 室外定位:高精度北斗RTK定位技术

    北斗RTK定位技术 xff0c 也称北斗差分定位技术 xff0c 利用我国自主研发的北斗卫星定位系统实现精确定位功能 定位精度可根据需要 xff0c 通过选择不同精度的人员定位终端来实现 在科技强国的战略驱动下 xff0c 北斗RTK定位技
  • 【高精度定位】RTK定位与RTD定位知识科普

    高精度定位一般指亚米级别或厘米级别的定位 xff0c 常见的室内有蓝牙AoA和UWB两种技术 xff0c 室外有北斗地基增强技术 xff0c 这些技术都是采用算法进行定位 工业4 0时代 xff0c 在资源和环境约束不断强化的背景下 xff
  • curl http或https上传下载

    curl的使用 注意如果是https请求需要带上ssl的库和curl库如下图 上传文件 回调函数 span class token keyword static span size t span class token function h
  • 层次遍历构建二叉树

    span class hljs keyword struct span TreeNode span class hljs keyword int span val span class hljs keyword struct span Tr
  • Jetson tx2 使用 jetpack 4.3刷机全过程

    1 首先准备一台安装有ubuntu 18 04 ubuntu16 04 系统的主机 xff08 host也就是笔记本 xff09 2 在nvidia官网注册一个nvidia的账号用于下载jetpack 4 3时使用 xff08 刷机过程中需
  • 2020/2/21 Linux Socket编程 高级篇——广播

    广播 xff1a 实现一对多的通信 SO BROADCAST选项 它控制了UDP套接字是否能发广播数据报 xff0c 选项类型是int xff0c 非零表示 是 只有UDP能用 xff0c TCP不能 如果是一个广播地址 xff0c 但SO
  • 大小端字节序(Big Endian和Little Endian)

    那么何为字节序 xff08 Endia xff09 呢 xff1f Big Endian是指低地址存放最高有效字节 xff08 MSB xff09 xff0c 而Little Endian则是低地址存放最低有效字节 xff08 LSB xf