• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    公众号

【转】gouintptrunsafePointeroffset()的使用

原作者: [db:作者] 来自: [db:来源] 收藏 邀请

 

原文:  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语言基本类型

类型名称 有无符号 占用位数
int8 Yes 8
int16 Yes 16
int32 Yes 32
int64 yes 64
uint8 No 8
uint16 No 16
uint32 No 32
uint64 No 64
int Yes 32或64,等于cpu位数
uint No 32或64,等于cpu位数
rune No 32,与uint32等价
byte No 8,与uint8等价
uintptr No 64,与uint64等价

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

一个可以指向任意类型的指针,不可以进行数值计算
有四种区别于其他类型的特殊操作:
1. 任意类型的指针值均可转换为 Pointer
2. Pointer 均可转换为任意类型的指针值
3. uintptr 均可转换为 Pointer
4. Pointer 均可转换为 uintptr

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}
}

  

 


鲜花

握手

雷人

路过

鸡蛋
该文章已有0人参与评论

请发表评论

全部评论

专题导读
上一篇:
go module学习笔记发布时间:2022-07-10
下一篇:
GO语言GORM的SQL构建器发布时间:2022-07-10
热门推荐
热门话题
阅读排行榜

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap