1 golang中的指针类型:unsafe.Pointer & uintptr
unsafe.PointerCvoid *uintptruintptrintunsafe.Pointer
unsafe.Pointeruintptruintptr
Go语言是强类型语言,指针也是具有明确类型的对象,进行严格类型检查,因此下面的代码会产生编译错误
package main
import (
"fmt"
)
func main() {
u := uint32(32)
i := int32(1)
fmt.Println(&u, &i) // 打印出地址
p := &i // p 的类型是 *int32
p = &u // &u 的类型是 *uint32,与 p 类型不同,不能赋值
p = (*int32)(&u) // 同样无效
fmt.Println(p)
}
unsafePointer
package main
import (
"fmt"
"unsafe"
)
func main() {
u := uint32(32)
i := int32(1)
fmt.Println(&u, &i)
p := &i
p = (*int32)(&u)
p = (*int32)(unsafe.Pointer(&u))
fmt.Println(p)
}
2 利用 unsafe.Pointer 突破私有成员
package main
import (
"fmt"
"text/template"
"unsafe"
)
// MyTemplate 定义和 template.Template 只是形似
type MyTemplate struct {
name string
parseTree *unsafe.Pointer
common *unsafe.Pointer
leftDelim string
rightDelim string
}
func main() {
t := template.New("Foo")
p := (*MyTemplate)(unsafe.Pointer(t))
p.name = "Bar" // 关键在这里,突破私有成员
fmt.Println(p, t)
}
输出结果
&{Bar <nil> <nil> } &{Bar <nil> <nil> }
t.nameBartemplate.Templatename
3 指针运算
首先定义结构V
type V struct {
i int32
j int64
}
指针运算
package main
import (
"poit/p"
"unsafe"
)
func main() {
var v *p.V = new(p.V) // 分配一段内存并返回一个指针,v是类型为p.V的一个指针
var i *int32 = (*int32)(unsafe.Pointer(v)) // 将指针v转成通用指针,再转成int32指针,不能直接将v转成int32类型的指针
*i = int32(98) // 改变v的私有成员i的值
var j *int64 = (*int64)(unsafe.Pointer(uintptr(unsafe.Pointer(v)) + uintptr(unsafe.Sizeof(int32(0))))) // 得到v.j在内存中的地址,unsafe.Sizeof得到一个值占用的字节空间
*j = int64(763) // 改变v的私有成员j的值
}
4 地址对齐
type W struct {
b byte // 1
i int32 // 4
j int64 // 8
}
func init() {
var w *W = new(W)
fmt.Printf("size=%dn", unsafe.Sizeof(*w)) // size=16
}
size=16size=13unsafe.Alignofunsafe.Alignof(w.b)
通过unsafe取值
package main
import (
"fmt"
"unsafe"
)
func main() {
var b []byte = []byte{'a', 'b', 'c'}
var c *byte = &b[0]
fmt.Println(*(*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(c)) + uintptr(1))))
}