我可以从Go中将*[]string
传递给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))
}
答案 0 :(得分:3)
不,这不可能。
请参阅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
本身包含许多(x
)指针,而*[]string
是另外一个指针。
答案 1 :(得分:2)
不允许将*[]string
传递给C,因为指向的内存包含字符串,而字符串包含指针。正如the cgo docs所说(强调我的意思)
请注意,某些Go类型的值,而不是该类型的零值, 始终包含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))
}