Golang Go语言中结构体里面有指针类型的字段,怎么计算其偏移量?

发布于 1周前 作者 caililin 来自 Go语言
  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 再次折磨了。


Golang Go语言中结构体里面有指针类型的字段,怎么计算其偏移量?

更多关于Golang Go语言中结构体里面有指针类型的字段,怎么计算其偏移量?的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html

10 回复

<br>package main<br><br>import (<br> "fmt"<br> "unsafe"<br>)<br><br>func main() {<br> stu := &amp;Stu{<br> pkg: &amp;Pkg{},<br> age: 1,<br> }<br> age := (*int)(unsafe.Pointer(uintptr(unsafe.Pointer(stu))+unsafe.Offsetof(stu.age)))<br> fmt.Println(*age)<br>}<br><br>type Stu struct {<br> pkg *Pkg<br> age int<br>}<br><br>type Pkg struct {<br><br>}<br>
验证可行

更多关于Golang Go语言中结构体里面有指针类型的字段,怎么计算其偏移量?的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


不我是没有办法访问到字段的,我能直接访问 stu.age ? 还用指针干毛线呀? 这里的*Pkg 的偏移量怎么算?

我是没有办法访问到字段的,我能直接访问 stu.age ? 还用指针干毛线呀? 这里的*Pkg 的偏移量怎么算?

64 位机器指针字段都是 8 字节,32 位是 4 字节,严谨一点可以通过判断机器环境 来选择取 4 还是 8

不知道什么场景需要访问其他包结构体里的私有字段,有一种比较 tricky 的方式是直接把结构体的(部分)定义复制过来。

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

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

当然,风险是如果以后这个结构体发生变化了,可能就没法正常运行了。

如果是无源码的 hack 场景,关键词:

data structure alignment
memory layouts

正解 。 已经拿到了。

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 的指针就好了

golang 有反射 reflect 这个库, 应该可以像 Python 那样根据字段名拿私有字段, 用偏移量拿说真的不是一个好习惯, 你这个例子前面只有一个字段问题还没那么大, 要是整多几个要字节对齐怎么办, 就算你全考虑到了知道怎么对齐拿到正确的字段, 这种根据编译器实现的编程方式都是坏习惯

在Go语言中,结构体(struct)是一种复合数据类型,允许你将多个不同类型的数据项组合在一起。当结构体中包含指针类型的字段时,计算其偏移量(offset)涉及到理解内存布局和对齐规则。

Go编译器会自动处理结构体的内存对齐,以优化访问速度和减少内存碎片。偏移量是指从结构体起始地址到某个字段地址的距离。

对于包含指针字段的结构体,计算偏移量的步骤如下:

  1. 理解对齐规则:Go语言中的每个类型都有一个对齐值,通常是该类型大小或其幂次方的2的最小值。指针类型的大小和对齐值通常是平台相关的(例如在64位系统上通常是8字节)。

  2. 使用unsafe包:Go的unsafe包提供了直接操作内存的功能,其中unsafe.Offsetof函数可以用来获取结构体字段的偏移量。注意,使用unsafe包要非常小心,因为它绕过了Go的类型安全机制。

  3. 编写代码

    package main
    
    import (
        "fmt"
        "unsafe"
    )
    
    type MyStruct struct {
        Field1 int
        Field2 *int
    }
    
    func main() {
        fmt.Println(unsafe.Offsetof(struct{}{}.Field2)) // 错误示例,应使用MyStruct实例
        // 正确方式是通过一个MyStruct实例来引用字段,但unsafe.Offsetof不允许直接这样用,
        // 通常是预先知道结构定义后手动计算或通过反射+unsafe结合使用(注意风险)。
    }
    

注意:直接计算指针字段的偏移量通常不是必要的,除非你在进行底层系统编程或实现某些特殊功能。在大多数情况下,应依赖Go的类型系统和内存管理机制。

回到顶部