前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >golang 利用指针导出变量 【原创】

golang 利用指针导出变量 【原创】

作者头像
CS逍遥剑仙
发布2018-04-28 12:00:57
1.5K0
发布2018-04-28 12:00:57
举报
文章被收录于专栏:禅林阆苑禅林阆苑

golang 利用指针导出变量

Write By CS逍遥剑仙 我的主页: www.csxiaoyao.com GitHub: github.com/csxiaoyaojianxian Email: sunjianfeng@csxiaoyao.com QQ: 1724338257

目录导航

  • golang 利用指针导出变量
    • 1 golang中的指针类型:unsafe.Pointer & uintptr
    • 2 利用 unsafe.Pointer 突破私有成员
    • 3 指针运算
    • 4 地址对齐

1 golang中的指针类型:unsafe.Pointer & uintptr

unsafe.Pointer 类似 Cvoid *,在golang中是用于各种指针相互转换的桥梁。uintptr 是golang的内置类型,能存储指针的整型,uintptr 的底层类型是 int,和 unsafe.Pointer 可相互转换。

  • unsafe.Pointer 用于转换不同类型指针,不可以参与指针运算
  • uintptr 用于指针运算,GC会自动回收 uintptr 类型的目标

Go语言是强类型语言,指针也是具有明确类型的对象,进行严格类型检查,因此下面的代码会产生编译错误

代码语言:javascript
复制
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)
}

unsafe 包提供的 Pointer 方法可以实现

代码语言:javascript
复制
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 突破私有成员

代码语言:javascript
复制
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)
}

输出结果

代码语言:javascript
复制
&{Bar <nil> <nil>  } &{Bar <nil> <nil>  }

t.name 也变成 Bar, 成功突破 template.Template 私有字段 name

3 指针运算

首先定义结构V

代码语言:javascript
复制
type V struct {
    i int32
    j int64
}

指针运算

代码语言:javascript
复制
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 地址对齐

代码语言:javascript
复制
type W struct {
    b byte  // 1
    i int32 // 4
    j int64 // 8
}
func init() {
    var w *W = new(W)
    fmt.Printf("size=%d\n", unsafe.Sizeof(*w)) // size=16
}

输出 size=16 而非 size=13,发生了对齐。struct中的对齐值是它成员中的最大对齐值。每个成员类型都有对齐值,可以用 unsafe.Alignof 方法来计算,如 unsafe.Alignof(w.b) 可以得到b在w中的对齐值。在b和i中间有3个填充,size=13+3=16

通过unsafe取值

代码语言:javascript
复制
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))))
}

【By CS逍遥剑仙】 未经允许不得转载:禅林阆苑 » golang 利用指针导出变量 【原创】

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2017-06-24分,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • golang 利用指针导出变量
    • 目录导航
      • 1 golang中的指针类型:unsafe.Pointer & uintptr
        • 2 利用 unsafe.Pointer 突破私有成员
          • 3 指针运算
            • 4 地址对齐
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档