在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
原文: https://blog.csdn.net/yzf279533105/article/details/97143100 package main import ( "fmt" "unsafe" "log" ) type Person struct { name string age int gender bool s rune } func main() { john := Person{"John", 30, true, 32} pp := unsafe.Pointer(&john) // 结构体的起始地址 pname := (*string)(unsafe.Pointer(uintptr(pp) + unsafe.Offsetof(john.name))) // 属性name的起始地址,转换为*string类型 page := (*int)(unsafe.Pointer(uintptr(pp) + unsafe.Offsetof(john.age))) // 属性age的起始地址,转换为*int类型 pgender := (*bool)(unsafe.Pointer(uintptr(pp) + unsafe.Offsetof(john.gender))) // 属性gender的起始地址,转换为*bool类型 log.Println("sizeof:", unsafe.Sizeof(john), unsafe.Sizeof(john.name), unsafe.Sizeof(john.age), unsafe.Sizeof(john.gender)) log.Println("Offset:") log.Println("name:", unsafe.Offsetof(john.name)) log.Println("age:", unsafe.Offsetof(john.age)) log.Println("gender:", unsafe.Offsetof(john.gender)) log.Println("s:", unsafe.Offsetof(john.s)) log.Println("sizeof s:", unsafe.Sizeof(john.s)) log.Println(pp) log.Println("pp:", uintptr(pp)) log.Println("name:", uintptr(pp) + unsafe.Offsetof(john.name)) log.Println("age:", uintptr(pp) + unsafe.Offsetof(john.age)) log.Println("gender:", uintptr(pp) + unsafe.Offsetof(john.gender)) log.Println("get pointer value") log.Println("name:",(*string)(unsafe.Pointer(uintptr(pp) + unsafe.Offsetof(john.name)))) log.Println("age:", (*int)(unsafe.Pointer(uintptr(pp) + unsafe.Offsetof(john.age)))) log.Println("gender:", (*bool)(unsafe.Pointer(uintptr(pp) + unsafe.Offsetof(john.gender)))) // 进行赋值 *pname = "Alice" *page = 28 *pgender = false fmt.Println(john) // {Alice 28 false} }
-------------------------------------------------------------- go语言基本类型 类型名称 有无符号 占用位数 rune 类型是 Unicode 字符类型,和 uint32 类型等价,通常用于表示一个 Unicode 字符。rune 和 uint32 可以互换使用。 byte 类型与uint8类型等价,byte类型一般用于强调数值是一个原始的内存数据而不是 一个小的整数。 uintptr 是一种无符号的整数类型,与uint64等价,范围:0 ~ 18446744073709551615,足以容纳任何指针值转换来的整型值。 uintptr类型只有在底层编程是才需要,特别是Go语言和C语言函数库或操作系统接口相交互的地方。GC 不把 uintptr 当指针,uintptr 无法持有对象。uintptr 类型的目标会被回收,所以不要声明uintptr类型的变量 不管它们的具体大小,int、uint和uintptr是不同类型的兄弟类型。其中int和int32也是 不同的类型, 即使int的大小也是32bit,在需要将int当作int32类型的地方需要一个显式的类型转换操作,反之亦然 unsafe.Pointer 一个可以指向任意类型的指针,不可以进行数值计算 unsafe 库让 golang 可以像C语言一样操作计算机内存,但这并不是golang推荐使用的,能不用尽量不用,就像它的名字所表达的一样,它绕过了golang的内存安全原则,是不安全的,容易使你的程序出现莫名其妙的问题,不利于程序的扩展与维护
示例1(unsafe.Pointer用来取地址,uintptr用来取地址的10进制数值) package main import ( "fmt" "unsafe" ) func main() { a := int(5) p := &a fmt.Println("p:", p) // a的地址,16进制形式 fmt.Println("unsafe.Pointer(&a):", unsafe.Pointer(&a)) // a的地址,16进制形式 fmt.Println("uintptr(upackage main import ( "fmt" "unsafe" ) func main() { a := int(5) p := &a fmt.Println("p:", p) // a的地址,16进制形式 fmt.Println("unsafe.Pointer(&a):", unsafe.Pointer(&a)) // a的地址,16进制形式 fmt.Println("uintptr(unsafe.Pointer(&a)):", uintptr(unsafe.Pointer(&a))) // a的地址,10进制形式 } nsafe.Pointer(&a)):", uintptr(unsafe.Pointer(&a))) // a的地址,10进制形式 }
PS:每次运行a的地址可能是不同的,但 unsafe.Pointer(&a) 和 uintptr(unsafe.Pointer(&a))的值是一样的,只是前者是指针类型,16进制,后者是整数类型,10进制,两者相等,这里 0xc00000a0b8,转换为10进制即 824633761976 示例2(地址计算,偏移,并修改) package main import ( "fmt" "unsafe" ) func main() { a := [4]int{0, 1, 2, 3} p1 := unsafe.Pointer(&a[1]) // p1指向a[1]的起始地址 // a[1]的地址类型转换为uintptr类型,后移2个元素的位置,这样移动到a[3]的起始地址位置 p3 := unsafe.Pointer(uintptr(p1) + 2 * unsafe.Sizeof(a[0])) *(*int)(p3) = 6 // 先将Pointer类型转换为*int类型,再赋值 fmt.Println("a =", a) // 打印出来结果是:a = [0 1 2 6] }
S:unsafe.Pointer 是桥梁,可以让任意类型的指针实现相互转换,也可以将任意类型的指针转换为 uintptr 进行指针运算 示例3(unsafe.Offsetof的使用) 该函数返回属性x的起始地址和结构体起始地址的字节数 func Offsetof(x ArbitraryType) uintptr package main import ( "fmt" "unsafe" ) type Person struct { name string age int gender bool } func main() { john := Person{"John", 30, true} pp := unsafe.Pointer(&john) // 结构体的起始地址 pname := (*string)(unsafe.Pointer(uintptr(pp) + unsafe.Offsetof(john.name))) // 属性name的起始地址,转换为*string类型 page := (*int)(unsafe.Pointer(uintptr(pp) + unsafe.Offsetof(john.age))) // 属性age的起始地址,转换为*int类型 pgender := (*bool)(unsafe.Pointer(uintptr(pp) + unsafe.Offsetof(john.gender))) // 属性gender的起始地址,转换为*bool类型 // 进行赋值 *pname = "Alice" *page = 28 *pgender = false fmt.Println(john) // {Alice 28 false} }
|
请发表评论