进制学习


进制对应的英文

name        中文名      含义        举例(以十进制为标准,10的转换)
binary      二进制      满2进1      1010
Octal       八进制      满8进1      12
Decimal     十进制      满10进1     10
Hex         十六进制    满16进1     a

进制转换在线工具

golang中进制之间的相互转换

首先看看go自带的包

“encoding/hex” “encoding/binary”

重点分析 2、10、16进制之间的相互转换

hex 分析

func Encode(dst, src []byte) int {
    for i, v := range src {
        dst[i*2] = hextable[v>>4]
        dst[i*2+1] = hextable[v&0x0f]
    }

    return len(src) * 2
}

Encode函数将src目标字节数组,转换成16进制形式的dst字节数组,数组长度翻倍

原理:将原来用一个字节表示的内容,用两个字节来表示,所以返回的dst是src的两倍长度

将原字节右移4位,得到高位内容(ascii码),放在第一个字节,原字节与0000 1111与,得到低位内容(ascii码),放到第二字节

func Decode(dst, src []byte) (int, error) {
    var i int
    for i = 0; i < len(src)/2; i++ {
        a, ok := fromHexChar(src[i*2])
        if !ok {
            return i, InvalidByteError(src[i*2])
        }
        b, ok := fromHexChar(src[i*2+1])
        if !ok {
            return i, InvalidByteError(src[i*2+1])
        }
        dst[i] = (a << 4) | b
    }
    if len(src)%2 == 1 {
        // Check for invalid char before reporting bad length,
        // since the invalid char (if present) is an earlier problem.
        if _, ok := fromHexChar(src[i*2]); !ok {
            return i, InvalidByteError(src[i*2])
        }
        return i, ErrLength
    }
    return i, nil
}

decode将16进制表达的字节组,还原成10进制表达的字节组

首先分别获取高低位表达的值,将第一个字节,也就是16进制高位的值进行左移4位,左移后的0~3bit就是10进制的前4个bit

将第二个字节,也就是16进制的低位与左移后的值或,得到的字节就是10进制表示的单个字节

最后对16进制的字符串长度进行最后验证,如果长度不正常返回err:odd length hex string

// EncodeToString returns the hexadecimal encoding of src.
func EncodeToString(src []byte) string {
    dst := make([]byte, EncodedLen(len(src)))
    Encode(dst, src)
    return string(dst)
}

此函数是将10进制的数组转成16进制,然后将新的字节组转成ascii码对应的字符串

func DecodeString(s string) ([]byte, error) {
    src := []byte(s)
    // We can use the source slice itself as the destination
    // because the decode loop increments by one and then the 'seen' byte is not used anymore.
    n, err := Decode(src, src)
    return src[:n], err
}

此函数是将字符串转成16进制形式的字节组,然后再数组转换成10进制形式

其它函数都是encode和decode函数的延伸,就不一一写了。

binary 分析

大小端介绍:通俗来讲,大端就是字节从左向右依次存放高低位,小端就是从左向右依次存放高低位

例子:

将 uint64类型的500存放到字节组中去,500的二进制形式是`0000 0001 1111 0100`
b := make([]byte, 8)
var value uint64 = 500
大端的处理方式:
binary.BigEndian.PutUint64(b, value)
结果
[0,0,0,0,0,1,244]
小端的处理方式:
binary.LittleEndian.PutUint64(b, value)
结果
[244,1,0,0,0,0,0,0]

其它存放函数大同小异,都是将对应bit长度的值存放到对应的字节中,以大端的putuint64为例

func (bigEndian) PutUint64(b []byte, v uint64) {
    _ = b[7] // early bounds check to guarantee safety of writes below
    b[0] = byte(v >> 56)
    b[1] = byte(v >> 48)
    b[2] = byte(v >> 40)
    b[3] = byte(v >> 32)
    b[4] = byte(v >> 24)
    b[5] = byte(v >> 16)
    b[6] = byte(v >> 8)
    b[7] = byte(v)
}

第一个字节存放 48~56bit
第二个字节存放 40~47bit
、
、
、
第八个字节存放 0~7bit