代码之家  ›  专栏  ›  技术社区  ›  mattes

指针字符串切片(*[]字符串)的Cgo指针传递规则?

  •  2
  • mattes  · 技术社区  · 6 年前

    *[]string 从Go到C,然后 append pointer passing spec ?

    Go代码可以将Go指针传递给C,前提是它所指向的Go内存不包含任何Go指针。

    示例代码:

    package main
    
    /*
    extern void go_callback(void*, char*);
    
    static inline void callback(void* stringSliceGoPointer) {
        go_callback(stringSliceGoPointer, "foobar");
    }
    */
    import "C"
    
    import (
        "fmt"
        "unsafe"
    )
    
    func main() {
        a := make([]string, 0)
        C.callback(unsafe.Pointer(&a)) 
        fmt.Println(a[0]) // outputs foobar
    }
    
    //export go_callback
    func go_callback(stringSliceGoPointer unsafe.Pointer, msg *C.char) {
        slice := (*[]string)(stringSliceGoPointer)
        *slice = append(*slice, C.GoString(msg))
    }
    
    2 回复  |  直到 6 年前
        1
  •  2
  •   MicahStetson    6 年前

    通过 *[]string the cgo docs 说(强调我的)

    请注意 一些Go类型的值 始终包括围棋指针。这是字符串的真实情况 ,切片、接口、通道、映射和函数类型。

    解决这个问题的一个方法是 []string 更间接地说,只有Go代码才知道它的地址。例如:

    package main
    
    /*
    extern void go_callback(int, char*);
    
    static inline void callback(int stringSliceRef) {
        go_callback(stringSliceRef, "foobar");
    }
    */
    import "C"
    
    import (
        "fmt"
    )
    
    // If you need to use these values concurrently,
    // you'll need more code to protect this.
    var stringSlices = make([][]string, 10)
    
    func main() {
        C.callback(0) 
        fmt.Println(stringSlices[0][0]) // outputs foobar
    }
    
    //export go_callback
    func go_callback(ref C.int, msg *C.char) {
        i := int(ref)
        stringSlices[i] = append(stringSlices[i], C.GoString(msg))
    }
    
        2
  •  3
  •   nilsocket    6 年前

    不,不可能。

    参考 this 进一步解释go数据类型。

    基本上Go中的字符串类型类似于这样。

    str := "hello"
    

     str:                0xad234e3b:
     ┌──────────┬─┐      ┌───┬───┬───┬───┬───┐
     |0xad234e3b|5|  ┌──>|104|101|108|108|111| -->[5]byte
     └────┬─────┴─┘  |   └───┴───┴───┴───┴───┘
          └──────────┘
    

    考虑一块:

    arr := string{"hi!","hello"}
    

    进一步的切片数据类型包含指针、长度、容量。

    arr:                   0xd2b564c7:        0xad234e40:
    ┌──────────┬─┬─┐       ┌──────────┬─┐     ┌───┬───┬──┐
    |0xd2b564c7|2|2|  ┌──> |0xad234e40|3|────>|104|105|33| -->[3]byte
    └────┬─────┴─┴─┘  |    ├──────────┼─┤     └───┴───┴──┘
         └────────────┘    |0xad234e4b|5|──┐  0xad234e4b:
                           └──────────┴─┘  |  ┌───┬───┬───┬───┬───┐
                                           └─>|104|101|108|108|111| -->[5]byte
                                              └───┴───┴───┴───┴───┘
    

    其中十六进制值表示地址。

    实际数据存储在 [x]byte .

    x

    很清楚 []string 它本身包含许多( )指针,而 *[]string