[转]浅谈字节序(Byte Order)及其相关操作

Socket 解决大端小端问题 下面是经过简化的BitConverter.ToInt16源码,其中的IsLittleEndian代表这台计算机是大端编码还是小端编码,不同的计算机编码方式会有不同。 阅读详情

摘自http://www.cnblogs.com/JeffreyZhao/archive/2010/02/10/byte-order-and-related-library.html

2010-02-10 23:05 by Jeffrey Zhao, 7642 visits, 网摘, 收藏, 编辑

最近在为Tokyo Tyrant写一个.NET客户端类库。Tokyo Tyrant公开了一个基于TCP协议的二进制协议,于是我们的工作其实也只是按照协议发送和读取一些二进制数据流而已,并不麻烦。不过在其中涉及到了“字节序”的概念,这本是计算机体系结构/操作系统等课程的基础,不过我还是打算在这里进行简单说明,并且对.NET中部分类库在此类数据流处理时的注意事项进行些许记录与总结。

字节序(Byte Order)

说到程序间的通信,说到底便是发送数据流。我们一般把字节(byte)看作是数据的最小单位。当然,其实一个字节中还包含8个比特(bit)──有时候我奇怪为什么很多朋友会不知道bit或是它和byte的关系。当我们拿到一系列byte的时候,它本身其实是没有意义的,有意义的只是“识别字节的方式”。例如,同样4个字节的数据,我们可以把它看作是1个32位整数、2个Unicode、或者字符4个ASCII字符。

同样我们知道,在一个32位的CPU中“字长”为32个bit,也就是4个byte。在这样的CPU中,总是以4字节对齐的方式来读取或写入内存,那么同样这4个字节的数据是以什么顺序保存在内存中的呢?例如,现在我们要向内存地址为a的地方写入数据0x0A0B0C0D,那么这4个字节分别落在哪个地址的内存上呢?这就涉及到字节序的问题了。

每个数据都有所谓的“有效位(significant byte)”,它的意思是“表示这个数据所用的字节”。例如一个32位整数,它的有效位就是4个字节。而对于0x0A0B0C0D来说,它的有效位从高到低便是0A、0B、0C及0D——这里您可以把它作为一个256进制的数来看(相对于我们平时所用的10进制数)。

而所谓大字节序(big endian),便是指其“最高有效位(most significant byte)”落在低地址上的存储方式。例如像地址a写入0x0A0B0C0D之后,在内存中的数据便是:

Big Endian

而对于小字节序(little endian)来说就正好相反了,它把“最低有效位(least significant byte)”放在低地址上。例如:

Little Endian

对于我们常用的CPU架构,如Intel,AMD的CPU使用的都是小字节序,而例如Mac OS以前所使用的Power PC使用的便是大字节序(不过现在Mac OS也使用Intel的CPU了)。此外,除了大字节序和小字节序之外,还有一种很少见的中字节序(middle endian),它会以2143的方式来保存数据(相对于大字节序的1234及小字节序的4321)。

关于字节序的详细说明,您可以参考Wikipedia里的Endianness条目。

相关.NET类库

BinaryWriter和BinaryReader

在.NET框架操作数据流的时候,我们往往会使用BinaryWriter和BinaryReader进行读写。这两个类中都有对应的WriteInt32或是ReadInt32方法,那么它们是如何处理字节序的呢?从MSDN上我们了解到BinaryReader使用小字节序读取数据。这意味着:

var stream = new MemoryStream(new byte[] { 4, 1, 0, 0 });
var reader = new BinaryReader(stream);
int i = reader.ReadInt32(); // i == 260

与之类似,自然BinaryWriter也是使用小字节序来写入数据。

BitConverter

有时候我们还会使用BitConverter来转化byte数组及一个32位整数(自然也包括其他类型),这也是涉及到字节序的操作,那么它们又是如何处理的呢?与BinaryWriter和BinaryReader的“固定策略”不同,BitConverter的行为是平台相关的。

首先,BitConverter有一个只读静态字段IsLittleEndian,它表示当前平台的字节序。由于我们为不同的CPU会安装不同的.NET类库,因此您现在如果通过.NET Reflector来查看这个字段会发现它被设置为一个常量true。那么接下来,BitConverter上的各个方便便会根据IsLittleEndian的值产生不同行为了,例如它的ToInt32方法:

public static unsafe int ToInt32(byte[] value, int startIndex)
{
    // ...

    fixed (byte* numRef = &(value[startIndex]))
    {
        if ((startIndex % 4) == 0)
        {
            return *(((int*)numRef));
        }
        if (IsLittleEndian)
        {
            return numRef[0] | (numRef[1] << 8) | (numRef[2] << 16) | (numRef[3] << 24);
        }

        return (numRef[0] << 24) | (numRef[1] << 16) | (numRef[2] << 8) | numRef[3];
    }
}

显然,这里会根据IsLittleEndian返回不同的值。

判断当前平台的字节序

在.NET Framework中BitConverter.IsLittleEndian字段是一个常量,也就是说它在编译期便写入了一个静态的值。那么我们如果想要通过代码来判断当前平台的字节序,又该怎么做呢?其实这很简单:

static unsafe bool IsLittleEndian()
{
    int i = 1;
    byte* b = (byte*)&i;
    return b[0] == 1;
}

这里我们通过检查32位整数1的第一个字节来确定当前平台的字节序。当然,我们也可以使用其他类型,例如:

static unsafe bool AmILittleEndian()
{
    // binary representations of 1.0:
    // big endian: 3f f0 00 00 00 00 00 00
    // little endian: 00 00 00 00 00 00 f0 3f
    // arm fpa little endian: 00 00 f0 3f 00 00 00 00
    double d = 1.0;
    byte* b = (byte*)&d;
    return (b[0] == 0);
}

这段代码来自mono的BitConverter类库,至于它为什么使用double而不是int,我也不是很清楚。

Buffer.BlockCopy方法

.NET类库中自带一个Buffer.BlockCopy方法,它的作用是将一个数组的字节——不是元素——复制到另一个数组中去。换句话说,一个长度为100的int数组经过完整的复制后,就变成了长度为50的long数组,因为一个int为4字节,而long为8字节。从文档上看,Buffer.BlockCopy是与字节序相关的,也就是说,同样的.NET代码在字节序不同的平台上得到的结果可能不同。因此,我建议在使用这个方法的时候多加小心。

面向特定字节序编程

我们知道,BitConverter的工作结果是和当前平台的字节序相关的,但是在很多时候,尤其是根据某个公开的协议进行通信编程的时候,是需要固定一个字节序的。例如Tokyo Tyrant便要求每个整数都以大字节序的方式来通信——无论是发送还是读取。为了保证.NET代码的平台无关性,我们不能直接使用BitConverter.GetBytes或ToInt32方法进行转化。那么我们该怎么办呢?最直观的方法自然是手动进行转换:

static int ReadInt32(Stream stream)
{
    var buffer = new byte[4];
    stream.Read(buffer, 0, 4);

    return buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24);
}

由于我们可以通过BitConverter.IsLittleEndian来得到当前平台的字节序,我们也可以用它进行判断:

static int ReadInt32(Stream stream)
{
    var buffer = new byte[4];
    stream.Read(buffer, 0, 4);

    if (BitConverter.IsLittleEndian)
    {
        Array.Reverse(buffer);
    }

    return BitConverter.ToInt32(buffer, 0);
}

static void WriteInt32(Stream stream, int value)
{
    var buffer = BitConverter.GetBytes(value);

    if (BitConverter.IsLittleEndian)
    {
        Array.Reverse(buffer);
    }

    stream.Write(buffer, 0, buffer.Length);
}

此外,我们知道BinaryWriter和BinaryReader都是依据小字节序进行读写的,因此我们也可以利用这点来读写数据流。要不,接下来就由您试试看如何?

C# 之工控机数据类型 高低位(大小端)、BitConverter、IsLittleEndian、字节数组转换(高低位) BitConverter.IsLittleEndian 本人电脑显示 True, 则 表示 数据存储是。单精度、32位、符合IEEE 754标准的浮点数。双精度、64位、符合IEEE 754标准的浮点数。》》False 高端低端 存储数据。浮点数不能用来表示精确的值,如货币 要用。16位、有符号的以二进制补码表示的整数。32位、有符号的以二进制补码表示的整数。64位、有符号的以二进制补码表示的整数。8位、有符号的以二进制补码表示的整数。boolean数据类型表示一位的信息。 阅读详情

相关推荐

计算机中的字节序(byte order)指的是在存储和表示多字节数据类型(如整数和浮点数)时,字节的顺序

计算机中的字节序(byte order)指的是在存储和表示多字节数据类型(如整数和浮点数)时,字节的顺序。在大端序中,高位字节存储在低位地址,而低位字节存储在高位地址。而在小端序中,低位字节存储在低位地址,高位字节存储在高位地址。例如,当两台计算机使用不同的字节序进行通信时,如果没有正确处理字节序,数据可能会被错误地解释。通过简单的代码检测,我们可以确定一台计算机的字节序,并相应地进行数据处理和通信。类型的指针是一个字节大小,我们可以通过检查指针所指向的值来确定第一个字节的存储位置。

TechNovaX的博客 386

一文带你秒懂 字节序(byte order),比特序(bit order),位域(bit field)

本文主要介绍比特序在大小端机器上的排布,以及网卡是如何收发比特的,文末简单介绍了位域的约定

清风 8574

飞书应用开发脚手架lark-harness:从零构建企业级机器人

在构建企业级应用时,开发脚手架是提升工程效率和规范性的关键工具。其核心原理在于通过预设的项目模板、最佳实践和通用模块封装,自动化处理项目初始化、配置管理和基础架构搭建。这种技术价值在于将开发者从重复性劳动中解放出来,确保团队技术栈统一,并降低维护成本。在Node.js生态中,脚手架常与Express或Koa等Web框架结合,用于快速构建Web服务、API接口和实时事件处理系统。具体到飞书开放平台开发场景,开发者需要处理OAuth 2.0授权、事件订阅验证、消息加解密等复杂且标准的流程。lark-harnes

weixin_30703911的博客 612

C# 大端序和小端序

大端序和小端序

tiankongzhicheng441x的博客 3179

ROS Noetic下Gazebo仿真:从零搭建两轮差速机器人(含ros_control配置避坑指南)

本文详细介绍了在ROS Noetic环境下,使用Gazebo从零搭建两轮差速机器人并进行仿真的完整流程。核心内容包括利用Xacro进行模块化建模,并重点解析了通过ros_control框架配置机器人运动控制的详细步骤与常见避坑指南,帮助开发者成功实现机器人在仿真环境中的差速驱动与运动控制。

game4的博客 620

Unity半透明物体景深失效?教你用双材质球方案完美解决(附完整Shader代码)

本文深入剖析了Unity中半透明物体导致景深效果失效的根本原因,即半透明物体默认不写入摄像机深度图。针对此问题,文章详细介绍了稳定高效的“双材质球”解决方案,通过为物体附加一个仅写入深度信息的不可见材质,完美修复景深效果,并提供了完整的Shader代码与实现脚本。

weixin_29010003的博客 381

浅谈字节序(Byte Order)及其相关操作(转自老赵)

最近在为Tokyo Tyrant写一个.NET客户端类库。Tokyo Tyrant公开了一个基于TCP协议的二进制协议,于是我们的工作其实也只是按照协议发送和读取一些二进制数据流而已,并不麻烦。不过在其中涉及到了“字节序”的概念,这本是计算机体系结构/操作系统等课程的基础,不过我

tianwailaibin的专栏 1283

GNSS - PPP软件 - GAMP 在VS2019/2022下完成调试、跑通程序(超详细!)

WIN32;_DEBUG;_CONSOLE;O_WARNINGS;ENAGLO;ENACMP;ENAGAL;ENAQZS;NFREQ=3。

qq_43381998的博客 8248

浅谈字节序(Byte Order)及其相关操作

<br /> <br />最近在为Tokyo Tyrant写一个.NET客户端类库。Tokyo Tyrant公开了一个基于 TCP协议的二进制协议,于是我们的工作其实也只是按照协议发送和读取一些二进 制数据流而已,并不麻烦。不过在其中涉及到了 “字节序”的概念,这本是计算 机体系结构/操作系统等课程的基础,不过我还是打算在这里进行简单说明,并且 对.NET中部分类库在此类数据流处理时的注意事项进行些许记录与总结。<br /> <br />字节序(Byte Order)<br /> <br />说到程序间的通

learningaginlearnin的专栏 704

内存越界一定会导致程序崩溃吗?详解内存越界

本文详细解释了内存越界不一定导致内存越界的问题,全面介绍了C++内存越界的相关内容。

dvlinker的技术专栏 2万+

OD图 arcgis曲线制作插件 od图曲线 路径图曲线制作插件 航线图曲线制作插件

在ArcGIS 10.2 中导入节点数据,打开插件,选择输入起始节点和目标节点的节点文件Point,以Name字段(地名)为连接线的起始字段和目标字段,(Input Table File)选择连接关系表格SDLine.csv,(Origin Column 和 Destination Column)为起始节点和目标节点,(Output Path)为输出路径,应选择.gdb数据库路径,否则容易报错,(Chord Coefficient)为连线的曲率,数值越大,曲率越高。运行环境:ArcGIS10.2。...

JData_Engineer的博客 2670

大、小端模式

一、大、小端模式的定义       在计算机系统中,我们是以字节为单位进行读、写的,每个地址单元都对应着一个字节,一个字节为 8bit。但是在C语言中除了8bit的char之外,还有16bit的short型,32bit的int/long型(要看具体的编译器)。另外,对于位数大于 8位的处理器,例如16位或者32位的处理器,由于寄存器宽度大于一个字节,那么必然存在着一个数据分布于多个字节德问题。因此就导致了大端存储模式和小 端存储模式。很多的ARM,DSP都为小端模式。有些ARM处理器还可

ml_liumangtu的专栏 1102

【二.图像处理核心技术】【5.形态学操作:腐蚀/膨胀/开闭运算】

想象一下,你拍了一张布满雪花点的老照片,或者扫描了字迹断裂的文档,这时候形态学操作就是你的像素整形师!它们能让模糊的边界变清晰,把断裂的笔画连起来,甚至从X光片里揪出癌细胞。今天我们要聊的,是计算机视觉界的"广场舞双雄"——腐蚀和膨胀。这俩操作就像给像素点们请了个健身教练,要么集体减肥(腐蚀),要么组团增肌(膨胀)。下次当你用美颜相机时,不妨会心一笑——这看似魔法的背后,正是形态学在默默耕耘。腐蚀的规则很简单:如果一个像素点周围的邻居不全白,它就"狗带"(变黑)。:先用砂纸打磨(腐蚀),再喷漆填补(膨胀)

商务合作|问题讨论|交流学习 请联系作者微信,加微信请务必注明来意,博客主页有联系方式 425

【C语言笔记】【小技巧系列】 判断字节序

BYTE_ORDER宏定义BYTE_ORDER表示当前机器的字节序,BYTE_ORDER的值被定义为,BIG_ENDIAN或者PDP_ENDIAN的其中之一。其中宏定义表示Little-Endian小端,宏定义BIG_ENDIAN表示Big-Endian大端,宏定义PDP_ENDIAN表示PDP-Endian。使用BYTE_ORDER需要包含头文件。使用BYTE_ORDER}或者#endif}==#endif}==#endif}宏定义与BYTE_ORDER,或者。...

2386

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

字节序(byte order)、比特序(bit order)、MSB/LSB、大端模式/小端模式 概念误混淆

发现之前概念一直混淆,今天就理清楚以作备忘。 前提:内存的读写永远从低地址开始读/写,从低到高!从低到高!从低到高! 内存的读写永远从低地址开始读/写!!! 1、字节序(byte order)、比特序(bit order) 字节序就是串行发送多字节时发送的顺序,比如a=0x12345678,按字节发送是0x12 0x34 0x56 0x78顺序还是0x78...0x12顺序 比特序同理但...

光明磊学习&积累的地方 1万+

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

上一篇: Macro中的#与##小结。。
下一篇: 解决:开启了debug但是Error: debugging information for 'myproject.exe' cannot be found or does not match. No symbols loaded.
wang37921
博客等级 码龄18年 14粉丝 31原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值