千家信息网

golang中unsafe 和 uintptr 指针怎么用

发表于:2026-11-02 作者:千家信息网编辑
千家信息网最后更新 2026年11月02日,这篇文章将为大家详细讲解有关golang中unsafe 和 uintptr 指针怎么用,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。1.golang中的指针类型三个
千家信息网最后更新 2026年11月02日golang中unsafe 和 uintptr 指针怎么用

这篇文章将为大家详细讲解有关golang中unsafe 和 uintptr 指针怎么用,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。

1.golang中的指针类型

三个类型
其实指针有三种:
一种是我们常见的*,用*去表示的指针;
一种是unsafe.Pointer,Pointer是unsafe包下的一个类型;
最后一种是uintptr,uintptr 这玩意是可以进行运算的也就是可以++-;

他们之间有这样的转换关系:
*<=> unsafe.Pointer <=> uintptr

有一点要注意的是,uintptr 并没有指针的语义,意思就是 uintptr 所指向的对象会被 gc 无情地回收。而 unsafe.Pointer 有指针语义,可以保护它所指向的对象在"有用"的时候不会被垃圾回收。
从这样的关系你大概就可以猜到,我们使用的指针*p转换成Pointer然后转换uintptr进行运算之后再原路返回,理论上就能等同于进行了指针的运算。我们下面就来实践一下。

2.具体操作

unsafe操作slice

func main() {s := make([]int, 10)s[1] = 2    p := &s[0]fmt.Println(*p)    up := uintptr(unsafe.Pointer(p)) //这里有可能会被回收 所以最好写成 (*int)unsafe.Pointer(uintptr(unsafe.Pointer(p))+unsafe.Sizeof(int(0)))up += unsafe.Sizeof(int(0)) // 这里不是up++p2 := (*int)(unsafe.Pointer(up))fmt.Println(*p2)}

输出:
0
2

从代码中我们可以看到,我们首先将指针指向切片的第一个位置,然后通过转换得到uintptr,操作uintptr + 上8位(注意这里不能++因为存放的是int,下一个元素位置相隔举例int个字节),最后转换回来得到指针,取值,就能取到切片的第二个位置了。

unsafe操作struct(可以访问私有属性)
我们知道如果一个结构体里面定义的属性是私有的,那么这个属性是不能被外界访问到的。我们来看看下面这个操作:

package maintype User struct {age  intname string}package mainfunc main() {user := &User{}fmt.Println(user)    s := (*int)(unsafe.Pointer(user))*s = 15up := uintptr(unsafe.Pointer(user)) + unsafe.Sizeof(int(0))namep := (*string)(unsafe.Pointer(up))*namep = "ljy"     fmt.Println(user)}

User是另外一个basic包中的结构体,其中的age是小写开头的,理论上来说,我们在外部没有办法修改age的值,但是经过上面这波操作之后,输出信息是:
&{0 }
&{10 xxx}
也就是说成功操作到了结构体的私有属性。

顺便提一句:创建结构体会被分配一块连续的内存,结构体的地址也代表了第一个成员的地址。

字符串和byte数组转换inplace
我们知道如果将字符串转换成[]byte非常方便

s := "123"a := []byte(s)

但是这样需要开辟额外的空间,那么如何实现原地的,不需要拷贝数据的转换呢?
其实从底层的存储角度来说,string的存储规则和[]byte是一样的,也就是说,其实指针都是从某个位置开始到一段空间,中间一格一格。所以利用unsafe就可以做到。

func main() {s := "123"a := []byte(s)print("s = " , &s, "\n")print("a = " , &a, "\n")    a2 := (*[]byte)(unsafe.Pointer(&s))print("a2 = " , a2, "\n")fmt.Println(*a2)}输出结果:s = 0xc420055f40a = 0xc420055f60a2 = 0xc420055f40[49 50 51]

我们可以看到s和a的地址是不一样的,但是s和a2的地址是一样的,并且a2已经是一个[]byte了。

存在的问题
其实这个转换是存在问题的,问题就在新的[]byte的Cap没有正确的初始化。
我们打印一下cap看一下

fmt.Println("cap a =", cap(a))  fmt.Println("cap a2 =", cap(*a2))  结果是:cap a = 32cap a2 = 17418400

问题的原因
在src/reflect/value.go下看

type StringHeader struct {        Data uintptr        Len  int}type SliceHeader struct {        Data uintptr        Len  int        Cap  int}

看到其实string没有cap而[]byte有,所以导致问题出现,也容易理解,string是没有容量扩容这个说法的,所以新的[]byte没有赋值cap所以使用了默认值。

问题解决

stringHeader := (*reflect.StringHeader)(unsafe.Pointer(&s))bh := reflect.SliceHeader{        Data: stringHeader.Data,        Len:  stringHeader.Len,        Cap:  stringHeader.Len,}return *(*[]byte)(unsafe.Pointer(&bh))

通过重新设置SliceHeader就可以完成

关于"golang中unsafe 和 uintptr 指针怎么用"这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,使各位可以学到更多知识,如果觉得文章不错,请把它分享出去让更多的人看到。

指针 问题 地址 属性 结构 也就是 位置 指向 篇文章 类型 私有 输出 运算 也就是说 字符 字符串 对象 更多 理论 空间 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 咖啡网 互联网科技公司经营范围 互联网科技有限公司经营范围 互联网核心科技是什么 关于新基建和互联网科技 金融科技 互联网金融 互联网科技公司名称 蓝色互联网科技 互联网汽车科技小镇 新华互联网科技2019 昊天互联网科技有限公司 和信科技工业互联网 电子科技大学互联网创业大赛 燊美集互联网科技有限公司 互联网公司黑科技创始人 互联网科技的全部知识 互联网企业科技类企业如何做账 互联网科技包装股份有限公司上市 扫呗互联网科技有限公司 吉林省码上互联网科技电话 苏州互联网科技贷款公司 天下捷融互联网科技 西藏七维空间互联网科技有限公司 互联网科技研发水平 浙南科技城互联网大厦建设工程 佛山市翊博互联网络科技有限公司 众安科技工业互联网合作 数字科技和互联网金融哪个好 上海互联网科技园景观 互联网大会出现的黑科技
0