V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
The Go Programming Language
http://golang.org/
Go Playground
Go Projects
Revel Web Framework
jeesk
V2EX  ›  Go 编程语言

golang 结构体里面有指针类型的字段, 怎么计算其偏移量?

  •  
  •   jeesk · 2022-06-23 22:34:38 +08:00 · 2123 次点击
    这是一个创建于 666 天前的主题,其中的信息可能已经有所发展或是发生改变。
    1. 结构体含有指针
    type Stu struct {
      pkg *Pkg
      age int 
    }
    
    type Pkg struct {
    
    }
    
    1. pkg 字段是个私有字段, 没有办法通过 unsafe.Offsetof() 拿到,只能通过 unsafe.SizeOf() , 但是这个 pkg 字段是个指针? 这个时候要怎么计算偏移量才能获取 age 的指针, 然后拿到 age 的值?
    2. 还是上面的例子,结构体里面有匿名字段
    type Stu struct {
      Pkg
      age int 
    }
    

    这种情况还能通过 unsafe.SizeOf(&Pkg{}) , 这种办法能拿到 pkg 的偏移量吗?

    上面两种情况要么我自己拿到的不对, 要么无处下手, 头大了。

    最近被 golang 再次折磨了。

    9 条回复    2022-06-24 09:51:01 +08:00
    chenxiankong
        1
    chenxiankong  
       2022-06-23 23:10:33 +08:00
    ```
    package main

    import (
    "fmt"
    "unsafe"
    )

    func main() {
    stu := &Stu{
    pkg: &Pkg{},
    age: 1,
    }
    age := (*int)(unsafe.Pointer(uintptr(unsafe.Pointer(stu))+unsafe.Offsetof(stu.age)))
    fmt.Println(*age)
    }

    type Stu struct {
    pkg *Pkg
    age int
    }

    type Pkg struct {

    }
    ```
    验证可行
    jeesk
        2
    jeesk  
    OP
       2022-06-23 23:26:01 +08:00
    @chenxiankong 不我是没有办法访问到字段的,我能直接访问 stu.age ? 还用指针干毛线呀? 这里的*Pkg 的偏移量怎么算?
    jeesk
        3
    jeesk  
    OP
       2022-06-23 23:26:28 +08:00
    @chenxiankong 我是没有办法访问到字段的,我能直接访问 stu.age ? 还用指针干毛线呀? 这里的*Pkg 的偏移量怎么算?
    chenxiankong
        4
    chenxiankong  
       2022-06-23 23:33:52 +08:00
    @jeesk 64 位机器指针字段都是 8 字节,32 位是 4 字节,严谨一点可以通过判断机器环境 来选择取 4 还是 8
    lujjjh
        5
    lujjjh  
       2022-06-24 00:17:02 +08:00   ❤️ 1
    不知道什么场景需要访问其他包结构体里的私有字段,有一种比较 tricky 的方式是直接把结构体的(部分)定义复制过来。

    比如获取 time.Time 结构体里的 ext 字段:

    https://gist.github.com/lujjjh/e92cb9904f8ec8bb42829cea0f6c2400

    当然,风险是如果以后这个结构体发生变化了,可能就没法正常运行了。
    0o0O0o0O0o
        6
    0o0O0o0O0o  
       2022-06-24 00:34:56 +08:00 via iPhone
    如果是无源码的 hack 场景,关键词:

    data structure alignment
    memory layouts
    jeesk
        7
    jeesk  
    OP
       2022-06-24 01:16:21 +08:00 via Android
    @chenxiankong 正解 。 已经拿到了。
    tj3u2l
        8
    tj3u2l  
       2022-06-24 02:36:38 +08:00
    type Stu struct {
    pkg *pkg
    age int
    }

    type pkg struct {
    test string
    }

    func main() {
    s := Stu{pkg: &pkg{test: "123"}, age: 10}
    fmt.Println(unsafe.Sizeof(new(pkg)))
    fmt.Println(*(*int)(unsafe.Pointer(uintptr(unsafe.Pointer(&s)) + unsafe.Sizeof(new(pkg)))))
    }

    就 Sizeof 的参数填 pkg 的指针就好了
    zone10
        9
    zone10  
       2022-06-24 09:51:01 +08:00   ❤️ 1
    golang 有反射 reflect 这个库, 应该可以像 Python 那样根据字段名拿私有字段, 用偏移量拿说真的不是一个好习惯, 你这个例子前面只有一个字段问题还没那么大, 要是整多几个要字节对齐怎么办, 就算你全考虑到了知道怎么对齐拿到正确的字段, 这种根据编译器实现的编程方式都是坏习惯
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   858 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 28ms · UTC 21:38 · PVG 05:38 · LAX 14:38 · JFK 17:38
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.