前言

asong    CCgithubstarasong

为什么有大小端之分

我一直都不理解,为什么要有大小端区分,尤其是小端,总是会忘记,因为他不符合人类的思维习惯,但存在即为合理,存在就有他存在的价值。这里有一个比较合理的解释:计算机中电路优先处理低位字节,效率比较高,因为计算机都是从低位开始的,所以计算机内部处理都是小端字节序。但是我们平常读写数值的方法,习惯用大端字节序,所以除了计算机的内部,其他场景大都是大端字节序,比如:网络传输和文件储存时都是用的大端字节序。

所以大小端问题很可能与硬件或者软件的创造者们有关,实际在计算机工业应用上,不同的操作系统和不同的芯片类型都有所不同。不同的系统设计不同,所以我们也没必要深究为什么要有这个区分,只需要知道他们的原理就好了。

什么是大端、小端

大端模式:高位字节排放在内存的低地址端,低位字节排放在内存的高地址端;

小端模式:低位字节排放在内存的低地址端,高位字节排放在内存的高地址端;

这么说也有点模糊,还是配个图来看更清晰:

0x1A2B3C4D0x4000

0x1A2B3C4D10x4D3C2B1A

因为大端、小端很容易混记,所以分享一个我自己记忆的小技巧:

大端:高低高低,也就是高位字节排放在内存低地址端,高地址端存在低位字节;

小端:高高低低;也就是高位字节排放在内存的高地址端,低位字节排放在内存的低地址端;

Go

计算机处理字节序的时候,不知道什么是高位字节,什么是低位字节。它只知道按顺序读取字节,先读取第一个字节,再读取第二个字节,所以说我就可以根据这个特性来读判断大小端。

GoC
Cunion
#include "stdio.h"


// big_endian: 1 
// little_endian: 2
int IsLittleEndian() {
    union {
        short value;
        char array[2];
    } u;
    u.value = 0x0102;
    if (u.array[0] == 1 && u.array[1] == 2){
        return 1;
    }else if (u.array[0] == 2 && u.array[1] == 1){
        return 2;
    }
    return -1;
}

int main() {
    
    int res;
    res = IsLittleEndian();
    printf("result is %d\n",res);
    if (res == 1) {
        printf("it is big endian");
    }
    if (res == 2){
        printf("it is little endian");
    }
    return 0;
}

// 运行结果(不同系统运行结果会有不同)
result is 2
it is little endian% 
GoGounionint32byteGounsafe
package main

import (
    "fmt"
    "unsafe"
)

func IsLittleEndian()  bool{
    var value int32 = 1 // 占4byte 转换成16进制 0x00 00 00 01 
  // 大端(16进制):00 00 00 01
  // 小端(16进制):01 00 00 00
    pointer := unsafe.Pointer(&value)
    pb := (*byte)(pointer)
    if *pb != 1{
        return false
    }
    return true
}

func main()  {
    fmt.Println(IsLittleEndian())
}
// 运行结果:ture

大小端字节序转化

armdsparmdsp
uint32
func SwapEndianUin32(val uint32)  uint32{
    return (val & 0xff000000) >> 24 | (val & 0x00ff0000) >> 8 |
        (val & 0x0000ff00) << 8 | (val & 0x000000ff) <<24
}

是的,你没看错,就是这么简单,这里也很简单,就不细讲了。

goencoding/binary
// use encoding/binary
// bigEndian littleEndian
func BigEndianAndLittleEndianByLibrary()  {
    var value uint32 = 10
    by := make([]byte,4)
    binary.BigEndian.PutUint32(by,value)
    fmt.Println("转换成大端后 ",by)
    fmt.Println("使用大端字节序输出结果:",binary.BigEndian.Uint32(by))
    little := binary.LittleEndian.Uint32(by)
    fmt.Println("大端字节序使用小端输出结果:",little)
}
// 结果:
转换成大端后  [0 0 0 10]
使用大端字节序输出结果: 10
大端字节序使用小端输出结果: 167772160
grpc
gRPCgRPCgRPCmessageheader
// msgHeader returns a 5-byte header for the message being transmitted and the
// payload, which is compData if non-nil or data otherwise.
func msgHeader(data, compData []byte) (hdr []byte, payload []byte) {
    hdr = make([]byte, headerLen)
    if compData != nil {
        hdr[0] = byte(compressionMade)
        data = compData
    } else {
        hdr[0] = byte(compressionNone)
    }

    // Write length of payload into buf
    binary.BigEndian.PutUint32(hdr[payloadLen:], uint32(len(data)))
    return hdr, data
}

结尾

在本文的最后我们再来做一下总结:

encoding/binary
githubstar

好啦,这篇文章就到这里啦,素质三连(分享、点赞、在看)都是笔者持续创作更多优质内容的动力!

创建了一个Golang学习交流群,欢迎各位大佬们踊跃入群,我们一起学习交流。入群方式:加我vx拉你入群,或者公众号获取入群二维码

结尾给大家发一个小福利吧,最近我在看[微服务架构设计模式]这一本书,讲的很好,自己也收集了一本PDF,有需要的小伙可以到自行下载。获取方式:关注公众号:[Golang梦工厂],后台回复:[微服务],即可获取。

我翻译了一份GIN中文文档,会定期进行维护,有需要的小伙伴后台回复[gin]即可下载。

翻译了一份Machinery中文文档,会定期进行维护,有需要的小伙伴们后台回复[machinery]即可获取。

我是asong,一名普普通通的程序猿,让我们一起慢慢变强吧。欢迎各位的关注,我们下期见~~~

推荐往期文章: