zoukankan      html  css  js  c++  java
  • unsafe.pointer 与 uintptr的区别

    unsafe.pointer 与 uintptr的区别

    unsafe.pointer与unintptr这两个东西在源码中出现的比较多,自己在业务上使用的比较少。但是面试中面试官还是挺喜欢问的。

    unsafe.pointer

    从名字来看它是不安全的和指针相关,unsafer.pointer主要的功能就是不同类型指针间的转换。

    不同类型之间不能直接转换

    func main() {
       var a *int8
       var b *int16
       a = new(int8)
       b = new(int16)
       *b = 10
       *a = *b
       fmt.Println(a)
    }
    复制代码
    
    1. 初始化一个指针类型的int8 a
    2. 初始化一个指针类型的int16 b
    3. 给指针b指向的内存赋值10
    4. 指针a内存赋值指针b的内存值

    结果:cannot use *b (type int16) as type int8 in assignment
    go是强类型语言,这种即使都是int,这样转换也是不行的,于是出现了unsafe.pointer。

    通过unsafe.pointer来花式转换

    var a *int8
    var b *int16
    a = new(int8)
    b = new(int16)
    *b = 10
    upb := unsafe.Pointer(b)
    b_int8ptr := (*int8)(upb)
    *a = *(b_int8ptr)
    fmt.Println(*a)
    复制代码
    
    1. 初始化一个指针类型的int8 a
    2. 初始化一个指针类型的int16 b
    3. 给指针b指向的内存赋值10
    4. 通过unsafe.pointer获取b的指针upb
    5. 把upb转成*int8指针 b_int8ptr
    6. 获取b_int8ptr的内存值赋值给a的地址指向的空间

    结果:10
    unsafer.pointer可以转换不同类型的指针。

    unintptr

    uintptr 实际上就是一个 uint 用来表示地址的。

    var a, b uintptr
    a = 10
    b = 10
    fmt.Println(a + b)
    复制代码
    

    同类型的地址也不能直接相加

    var a, b *int
    a, b = new(int), new(int)
    c:=a+b  //invalid operation: a + b (operator + not defined on pointer)
    复制代码
    

    同类型的地址也不能直接相加

    var a, b *int
    a, b = new(int), new(int)
    c := unsafe.Pointer(a) + unsafe.Pointer(b) // invalid operation: unsafe.Pointer(a) + unsafe.Pointer(b) (operator + not defined on unsafe.Pointer)
    复制代码
    

    结合uintptr来做地址之间的运算

    var a, b *int
    a, b = new(int), new(int)
    c := uintptr(unsafe.Pointer(a)) + uintptr(unsafe.Pointer(b))
    fmt.Println(c)
    复制代码
    

    unsafe和uintptr的一些组合操作

    type User struct {
       Name string
       Age  int8
    }
    func main() {
       u := &User{}
       uAddress := unsafe.Pointer(u)
       ageOffset := unsafe.Offsetof(u.Age)
       agePtr := unsafe.Pointer(uintptr(uAddress) + ageOffset)
       *((*int)(agePtr)) = 10
       fmt.Println(u.Age)
    }
    复制代码
    
    1. 通过unsafe.Pointer获取u的地址uAddress
    2. 通过unsafe.Offsetof获取u.age的偏移量
    3. uintptr转换uAddress 加上age的偏移量就找到了age的地址agePtr
    4. agePtr转成指针型int,然后取其内存空间,赋值10

    结合unsafe和uintptr也可以对某些变量赋值,整个流程看下来比较复杂。

    总结

    1. 任何类型的指针都可以被转化为Pointer
    2. Pointer可以被转化为任何类型的指针
    3. uintptr可以被转化为Pointer
    4. Pointer可以被转化为uintptr
    5. unsafe.pointer是普通指针类型,用于转换不同类型的指针,不能进行指针运算,不能读取内存存储的值,必须转换到某一类型的普通指针。
    6. uintptr用于指针运算,GC不把uintptr当指针,uintptr无法持有对象,uintptr类型的目标会被回收。

    作者:假装懂编程
    链接:https://juejin.cn/post/6991438499958243335

  • 相关阅读:
    ES6解构赋值
    ES6中的Symbol类型
    两个列表合并成字典
    python关于列表转为字典的两个小方法
    break、continue和return的使用
    进度条的实现
    md5加密
    dict字典方法
    用户相关的文件、解析以及命令的使用
    linux的根目录
  • 原文地址:https://www.cnblogs.com/maomaomaoge/p/15096430.html
Copyright © 2011-2022 走看看