⭐在go里面使用unsafe标准库

使用了unsafe包,该代码可能会绕过Go语言的类型安全检查,因此在实际开发中应该谨慎使用

Alignof

获取指定类型的对齐方式。对齐方式指的是编译器在分配内存时,将数据类型存储在内存中的起始地址的对齐方式

函数原型

func Alignof(variableType T) uintptr

其中,variableType是需要获取对齐方式的类型,可以是一个基本类型,也可以是一个结构体或数组等自定义类型。uintptr是一个无符号整数类型,可以用来表示指针或内存地址的整数值

Alignof函数返回的是指定类型的对齐方式,以字节为单位。例如,对于一个64位整数类型int64,通常的对齐方式为8字节(64位),因此调用Alignof(int64)会返回8

示例代码

var i int
var f float64
var s string
var m map[string]string
fmt.Printf("int size %d\n", unsafe.Alignof(i))
fmt.Printf("float64 size %d\n", unsafe.Alignof(f))
fmt.Printf("string size %d\n", unsafe.Alignof(s))
fmt.Printf("map size %d\n", unsafe.Alignof(m))

输出

int size 8
float64 size 8
string size 8
map size 8

Sizeof

获取变量大小

函数原型

func Sizeof(x ArbitraryType) uintptr

示例代码

var i int
var f float64
var s string
var a []int
var m map[string]string
fmt.Printf("int size %d\n", unsafe.Sizeof(i))
fmt.Printf("float64 size %d\n", unsafe.Sizeof(f))
fmt.Printf("string size %d\n", unsafe.Sizeof(s))
fmt.Printf("array size %d\n", unsafe.Sizeof(a))
fmt.Printf("map size %d\n", unsafe.Sizeof(m))

输出

int size 8
float64 size 8
string size 16
array size 24
map size 8


Offsetof

unsafe.Offsetof函数可以获取指定结构体成员变量的偏移量(offset)。偏移量指的是该成员变量相对于结构体起始地址的偏移量,以字节为单位

函数原型

func Offsetof(x ArbitraryType) uintptr

示例代码

  • 获取一个不存在的struct属性会报错 ``` type Person struct { name string age int }

p := Person{“John Doe”, 30}

fmt.Printf(“%d\n”, unsafe.Offsetof(p.name))

fmt.Printf(“%d\n”, unsafe.Offsetof(p.age))

输出

0 16

---

**[]byte类型的切片转换string类型**

代码示例

var bs = []byte{‘h’, ‘e’, ‘l’, ‘l’, ‘o’, ‘,’, ‘ ‘, ‘w’, ‘o’, ‘r’, ‘l’, ‘d’, ‘!’}

sr := (string)(unsafe.Pointer(&bs))

fmt.Printf(“%s\n”, sr);

跟(string)转换变量效果类似

输出

hello, world!

---

**获取StringHeader**

StringHeader 用于描述字符串的底层实现

代码示例

var foo = “hello world!”

header := (*reflect.StringHeader)(unsafe.Pointer(&foo))

fmt.Printf(“len %d\n”, header.Len)

fmt.Printf(“ptr %x\n”, header.Data)


输出

len 12 ptr 10a98cf

---
**获取SliceHeader**

SliceHeader是Go语言标准库unsafe中的一个结构体类型,用于描述切片的底层实现

代码示例

var nations = []string{“China”, “Japan”, “Canada”, “Italy”}

header := (*reflect.SliceHeader)(unsafe.Pointer(&nations))

fmt.Printf(“len %d\n”, header.Len) fmt.Printf(“cap %d\n”, header.Cap) fmt.Printf(“ptr %x\n”, header.Data)


输出

len 4 cap 4 ptr c000064f30

---
**通过指针遍历切片**

代码示例

var bs = []byte{‘h’, ‘e’, ‘l’, ‘l’, ‘o’, ‘,’, ‘ ‘, ‘w’, ‘o’, ‘r’, ‘l’, ‘d’, ‘!’}

ptr := unsafe.Pointer(&bs[0])

header := (*reflect.SliceHeader)(unsafe.Pointer(&bs))

offset := 0

for offset < header.Len { next := (*byte)(ptr)

fmt.Println(string(*next))

ptr = unsafe.Pointer(uintptr(ptr) + unsafe.Sizeof(bs[offset]))

offset++ } ```

输出

hello, world!