【问题标题】:Pointer arithmetic in GoGo中的指针算法
【发布时间】:2015-12-18 11:51:43
【问题描述】:

考虑到您可以(想不出一个很好的表达方式,但是)在 Go 中操作指针,是否可以像在 C 中那样执行指针运算,比如迭代数组?我知道这些天循环对于这类事情很好,但我只是好奇它是否可能。

【问题讨论】:

    标签: pointers go pointer-arithmetic


    【解决方案1】:

    没有。来自Go FAQ

    为什么没有指针运算?

    安全。如果没有指针算法,就有可能创建一种永远不会得出错误成功的非法地址的语言。编译器和硬件技术已经发展到使用数组索引的循环可以与使用指针算法的循环一样高效的程度。此外,指针算法的缺乏可以简化垃圾收集器的实现。

    话虽如此,您可以使用 unsafe 包解决此问题,但只是不要

    package main
    
    import "fmt"
    import "unsafe"
    
    func main() {
        vals := []int{10, 20, 30, 40}
        start := unsafe.Pointer(&vals[0])
        size := unsafe.Sizeof(int(0))
        for i := 0; i < len(vals); i++ {
            item := *(*int)(unsafe.Pointer(uintptr(start) + size*uintptr(i)))
            fmt.Println(item)
        }
    }
    

    https://play.golang.org/p/QCHEQqy6Lg

    【讨论】:

    • 如果您这样做,请使用//go:nosplit,否则您可能会破坏 gc 的状态。
    • 我不明白为什么 //go:nosplit 会以某种方式在这里有所作为。 //go:nosplit 注释告诉编译器在进入函数时不要检查堆栈溢出。这样做的副作用是垃圾收集器在进入函数时不会运行。但是这些指针在函数内部被操纵,而 go:nosplit 不会影响它。记录何时可以安全地在 unsafe.Pointer 和 uintptr 之间转换的问题是 golang.org/issue/8994
    【解决方案2】:

    从 Go 1.17 开始,我们现在有了 unsafe.Add,这使它更容易一些:

    package main
    
    import (
        "unsafe"
    )
    
    func main() {
        vals := []int{10, 20, 30, 40}
    
        ptrStart := unsafe.Pointer(&vals[0])
        itemSize := unsafe.Sizeof(vals[0])
    
        for i := 0; i < len(vals); i++ {
            item := *(*int)(unsafe.Add(ptrStart, uintptr(i)*itemSize))
            println(item)
        }
    }
    

    Playground.

    【讨论】:

      猜你喜欢
      • 2020-09-23
      • 2016-07-12
      • 2011-04-01
      • 2021-07-14
      • 1970-01-01
      • 2016-03-20
      • 2021-11-02
      相关资源
      最近更新 更多