首先从byte聊起:
最早的计算机有 4-bit、6-bit、7-bit 等好多种。IBM在 1950 年设计 IBM 7030 Stretch 的时候引入 byte 的概念,byte表示访问内存的最小单位。
布鲁克斯被问到:“您认为自己最大的技术成就是什么?”
Brooks回答说:“我做出的最重要的决定是将IBM 360系列从6位更改为8位字节,从而允许使用小写字母。这种变化传播到了所有地方。
微型计算机要到 1970 年代早期才出现,那个时候8位byte已经用了将近十年了,自然大家就继续使用了。
大端和小端:
byte表示访问内存的最小单位且为8个bit,这个是人为规定出来的,延续至今是个历史原因。有最小的储存单位,就有更大的储存单位,如int ,long ,一般情况下int 是32位的,long是64位的。
那 int 和 long 是由最小访问内存单位byte构成的,那么问题就来了,当byte构成 int 和 long时,顺序怎么放?于是就有了大端的摆放方式 和 小端的摆放方式,如下:
那其实,这里就可以看到,所谓的大小端是针对,比byte大的单位,内部的byte如何摆放的。
什么时候要进行大小端字节序的转换?
出现了大端和小端,说明是出现的分歧,有的地方,觉得小端好,有的地方,觉得大端好。那既然有了分歧,作为程序员,就多了一份转换的工作。
那那些地方用的大端那些地方用的小端?
Motorola的PowerPC系列CPU采用Big Endian方式存储数据。
Intel的x86系列CPU采用Little Endian方式存储数据。
ARM既可以工作在大端模式,也可以工作在小端模式。在ARM上,我见到的都是用Little Endian方式存储数据。
Windos(x86,x64)和Linux(x86,x64)都是Little Endian操作系统
C/C++语言编写的程序里数据存储顺序是跟编译平台所在的CPU相关的。
JAVA编写的程序则唯一采用Big Endian方式来存储数据。
所有网络协议也都是采用Big Endian的方式来传输数据的。所以有时我们也会把Big Endian方式称之为网络字节序。
知道了这些,大概就知道什么时候需要转换了。举几个例子:
c# 到网络
c#在windows平台上是小端字节序(Windos(x86,x64)和Linux(x86,x64)都是Little Endian操作系统,不止是c#)。网络发送字节流是按大端序发送,也就是从左到右发送,和c#的小端序相反,造成网关不能正常识别协议。所以需要转换。
c# 到JAVA
在你的C#程序传给JAVA程序之前有必要进行字节序的转换工作。
字符串不需要大小端转换
上面的转换其实针对的都是数字,应为顺序变了,数学的大小就变了,但是字符串不同,它有自己的编码顺序(UTF8 ASCC gb2312 等等)
所以,我们可以看到这样的代码:
/// <summary>
/// 发送消息
/// </summary>
/// <param name="msg"></param>
/// <returns></returns>
public static byte[] BuildMsgCmd(string msg)
{
var arr = new List<byte> { };
//转为byte数组并进行大小端转换
var byteHeader = BitConverter.GetBytes(HeartMsg).Reverse().ToList();
//字符串不用进行大小端转换
var byteMsg = Encoding.UTF8.GetBytes(msg);
//转为byte数组并进行大小端转换
var byteLength = BitConverter.GetBytes((ushort)byteMsg.Length).Reverse().ToList();
arr.AddRange(byteHeader);
arr.AddRange(byteLength);
arr.AddRange(byteMsg);
return arr.ToArray();
}
数字相关的都进行了,大小端转换,字符串就不用了。
参考资料: