一、go的指针
pointer type、 uintptr和unsafe.Pointer
pointer type: 指针类型,有具体基础类型指针的名称,如
*int
叫整型指针类型uintptr: 一个无符号整数,用于存放地址。只是一个地址,没有对地址处的数据做任何类型解释,可以做运算,如:
var p uintptr p+=1
。当uint看即可-
unsafe.Pointer: unsafe包中的一个类型,指向任意指针类型的指针类型,相当于C中void*。它有四钟其他类型的特殊操作:
- 任意类型指针能转化为unsafe.Pointer
- unsafe.Pointer能够转化为任意类型的指针
- unsafe.Pointer可转为uintptr
- uintp可以转为unsafe.Pointer
因此,一个指针类型和uintptr转化要通过unsafe.Pointer,所有go中指针操作比C麻烦太多。
示例1 将[]byte中两个元素转为uint16值,可以使用 encoding/binary包中的binary.LittleEndian.Uint16函数转化,这里只是为了说明指针的转化
b := []byte{0x01, 0x02, 0x3, 0x4}
var u16 uint16
pb := unsafe.Pointer(&b[1]) //pb指向b第二个元素的地址,注:&b不是slice的第一元素的地址,要用&b[0],如果为数组 [4]byte{}则&b为第一个元素的地址,原因参与雨痕的go学习笔记。
u16 = *((*uint16)(pb)) //将b的2,3元素转为一个uint16的数,小端模式0x0302,大端模式0x0203; intel和amd CPU都是小段模式
fmt.Printf("u16:%#04x\n", u16) //0x0302
- 示例2 通过uintptr的运算取到数据
var u16 uint16
var p uintptr
b := [4]byte{0x01, 0x02, 0x3, 0x4}
//uintptr和指针类型不能直接转换
//p = uintptr(&b) //cannot convert &b (type *[4]byte) to type uintptr
//u16 = *((*uint16)(p + 2)) //cannot convert p + 2 (type uintptr) to type *uint16
pb := unsafe.Pointer(&b)
p = uintptr(pb)
fmt.Printf("p:%p\n", p) //p:0xc000071f5c
p++
pb = unsafe.Pointer(p)
u16 = *((*uint16)(pb))
fmt.Printf("u16:%#04x\n", u16) //u16:0x0302