如何复制*C.char?

问题描述 投票:0回答:1

*C.char 的 mempcy() 等价于什么?

我有一个函数,可以使用

-buildmode=c-shared
:

从 C 调用
myGoStr := "blabla"

//export GetString
func GetString(text *C.char) {
 memcpy(text, myGoStr)
}
  • 内存在C中分配
  • 字符串是golang类型

如何将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

go cgo
1个回答
0
投票

有多种方法可以实现您想要的目标,但问题是,无论哪种方式都是不安全的——无论哪种方式。这样做的原因是

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 端是安全的。

© www.soinside.com 2019 - 2024. All rights reserved.