*C.char 的 mempcy() 等价于什么?
我有一个函数,可以使用
-buildmode=c-shared
: 从 C 调用
myGoStr := "blabla"
//export GetString
func GetString(text *C.char) {
memcpy(text, myGoStr)
}
如何将Go字符串复制到
*C.char
后面的C分配内存?
我很了解所有的C.String函数(https://pkg.go.dev/cmd/cgo#hdr-Go_references_to_C),但我不想让Go分配内存,我想工作直接使用 C 应用程序给出的 C 指针。
我发现的唯一方法是:
cStr := C.CString(text)
C.strcpy(text, cStr)
C.free(unsafe.Pointer(cStr))
但是这太夸张了,因为它涉及2个副本(
C.CString
和C.strcpy
)
有多种方法可以实现您想要的目标,但问题是,无论哪种方式都是不安全的——无论哪种方式。这样做的原因是
memcpy
已经 不安全了(在 Go 的思维框架中),因为它的第三个参数——要复制的字节数——不是以某种方式从该函数的其余参数中获得的(Go 的 copy
确实)。
所以,是的,你可以避免通常的 Go 的
unsafe
舞蹈,从你的 *C.char
中构建一个切片,传递给 copy
并获得那种温暖舒适的安全感,但还有另一种解决方案 - 例如直接调用 memcpy
直接 - 无论如何都会依赖所说的*C.char
指向一个具有足够可用空间的内存块,以包含至少与Go源字符串中的字节数加一,但没有任何保证。
我的意思是,如果你想走这条路,你可以这样做:
/*
#include <string.h>
static void memcpy_from_go(char *dst, _GoString_ src)
{
memcpy(dst, src.p, src.n);
}
*/
import "C"
const myGoStr = "blabla"
//export GetString
func GetString(text *C.char) {
C.memcpy_from_go(text, myGoStr)
// (!) note that no NUL terminator is placed into the destination block
}
func main() {}
但是由于无论如何都不安全,我认为类似的
func strcpyToC(dst *C.char, src string) {
n := len(src)
ds := unsafe.Slice((*byte)(unsafe.Pointer(dst)), n+1)
copy(ds, src)
ds[n] = 0
}
//export GetString
func GetString(text *C.char) {
strcpyToC(text, myGoStr)
}
更清晰,但同样不安全。
换句话说,你不能在 Go 端对 C 端进行内存操作,并且仍然声称你的 Go 端是安全的。