Go语言中的字节序

Python018

Go语言中的字节序,第1张

Go中的binary包实现了简单的数字与字节序列的转换以及变长值的编解码

package main

import ( "fmt" "bytes" "encoding/binary" ) func main(){ n := 0x12345678 bytesBuffer := bytes.NewBuffer([]byte{}) //BigEndian 大端顺序存储 LittleEndian小端顺序存储 binary.Write(bytesBuffer, binary.BigEndian, int32(n)) data:=bytesBuffer.Bytes() fmt.Printf("[0]: %#x addr:%#x\n",data[0],&data[0]) fmt.Printf("[0]: %#x addr:%#x\n",data[1],&data[1]) fmt.Printf("[0]: %#x addr:%#x\n",data[2],&data[2]) fmt.Printf("[0]: %#x addr:%#x\n",data[3],&data[3]) }

输出

[0]: 0x12 addr:0xc042010248 [1]: 0x34 addr:0xc042010249 [2]: 0x56 addr:0xc04201024a [3]: 0x78 addr:0xc04201024b

也可以使用下面的方式

n := 0x12345678 var data []byte = make([]byte,4) //操作的都是无符号整型 binary.BigEndian.PutUint32(data,uint32(n))

可以使用下面的方式判断当前系统的字节序类型

const INT_SIZE int = int(unsafe.Sizeof(0))

//判断我们系统中的字节序类型 func systemEdian() { var i int = 0x1 bs := (*[INT_SIZE]byte)(unsafe.Pointer(&i)) if bs[0] == 0 { fmt.Println("system edian is little endian") } else { fmt.Println("system edian is big endian") } }

当分别处于大小端模式下的内容存放如下 (1)大端模式存储(存储地址为16位) 地址 数据 0x0004(高地址) 0x44 0x0003 0x33 0x0002 0x22 0x0001(低地址) 0x11 (2)小端模式存储(存储地址为16位) 地址 数据 0x0004(高地址) 0x11 0x0003 0x22 0x0002 0x33 0x0001(低地址) 0x44 在前面也简单阐述了大小端序的定义并结合简单实例来说明,接下来会给出详细实例来说明: 1、大端序(Big-Endian):或称大尾序 一个类型: int32 的数 0X0A0B0C0D的内存存放情况 数据是以8bits为单位 2、小端序(little-endian):或称小尾序 比如0x00000001 大端序:内存低比特位 00000000 00000000 00000000 00000001 内存高比特位 小端序:内存低比特位 10000000 00000000 00000000 00000000 内存高比特位 其实在前面罗列出那么东西,最终是为了接下来讲述的在golang中涉及到网络传输、文件存储时的选择。一般来说网络传输的字节序,可能是大端序或者小端序,取决于软件开始时通讯双方的协议规定。TCP/IP协议RFC1700规定使用“大端”字节序为网络字节序,开发的时候需要遵守这一规则。默认golang是使用大端序。详情见golang中包encoding/binary已提供了大、小端序的使用 输出结果: 16909060 use big endian: int32 to bytes: [1 2 3 4]### [0001 0002 0003 0004] bytes to int32: 16909060 16909060 use little endian: int32 to bytes: [4 3 2 1] ### [0004 0003 0002 0001] bytes to int32: 16909060 在RPCX框架中关于RPC调用过程涉及的传递消息进行编码的,采用的就是大端序模式

golang语言本身就是c的工具集,开发c的程序用到的大部分结构体,内存管理,携程等,golang基本都有,他只是在这个基础上又加了一些概念这里说一个很小的问题,就是字节数组转string的问题,网上大部分都是这样转的(包括google上):string(p[:]),这个转完了是有问题的,我们再来看一下string这个结构体:

struct String

{

byte* str

intgo len

}

这个结构体让我想起了nginx的string,他是这样定义的:

typedef struct {

size_t len

u_char *data

} ngx_str_t

golang里边 string的概念其实不是以前遇到\0结尾的概念了,他其实就是一块连续的内存,首地址+长度,上面那样赋值,如果p里边有\0,他不会做处理这个时候,如果再对这个string做其他处理就可能出问题了,比如strconv.Atoi转成int就有错误,解决办法就是需要自己写一个正规的转换函数:

func byteString(p []byte) string {

for i := 0i <len(p)i++ {

if p[i] == 0 {

return string(p[0:i])

}

}

return string(p)

}

这样就不会出问题了