从 Dynamic Loaded Golang 到 CPP 的未知字符串
Unknown string from Dynamic Loaded Golang to CPP
所以,我尝试 运行 我的 go 代码在 C++ 项目上动态加载。它工作得很好,除了返回值上有一些不需要的字符串。正如我解释的那样,我从 Go 那里得到了一些不需要的信息。
我的代码:
package main
import "C"
func main() {}
//export GetTestString
func GetTestString() string {
return "test"
}
我用以下方法构建它:
go build -buildmode=c-shared -o test.so test.go
使用此功能将其动态加载到我的 CPP 项目中:
typedef struct { const char *p; ptrdiff_t n; } GoString;
void getTestString() {
void *handle;
char *error;
handle = dlopen ("./test.so", RTLD_LAZY);
if (!handle) {
fputs (dlerror(), stderr);
exit(1);
}
// resolve getTestString symbol and assign to fn ptr
auto getTestString = (GoString (*)())dlsym(handle, "GetTestString");
if ((error = dlerror()) != NULL) {
fputs(error, stderr);
exit(1);
}
// call GetTestString()
GoString testString = (*getTestString)();
printf("%s\n", testString.p);
// close file handle when done
dlclose(handle);
}
输出为:
"testtrue ...\n H_T= H_a= H_g= MB, W_a= and cnt= h_a= h_g= h_t= max= ptr siz= tab= top= u_a= u_g=, ..., fp:argp=falsefaultgcingpanicsleepsse41sse42ssse3 (MB)\n addr= base code= ctxt: curg= goid jobs= list= m->p= next= p->m= prev= span= varp=(...)\n, not SCHED efenceerrno objectpopcntscvg: selectsweep (scan (scan) MB in dying= locks= m->g0= nmsys= s=nil\n, goid=, size=, sys: GODEBUGIO waitSignal \ttypes \tvalue=cs fs gctracegs panic: r10 r11 r12 r13 r14 r15 r8 r9 rax rbp rbx rcx rdi rdx rflags rip rsi rsp runningsignal syscallunknownwaiting etypes goalΔ= is not mcount= minutes nalloc= newval= nfree..."
当通过指向 C 的指针传递字符串时,您需要在 GoString
中使用长度 (n
) 来获取正确数量的字符,因为 p
处的字符串不是 [=15= ]
终止。或者您可以 return *C.char
而不是 string
并使用 C.CString()
在 C 堆上分配副本(然后您负责在使用后释放)。请参阅 Cgo 文档 here。
你的代码中发生的事情是 printf()
简单地打印从 string.p
指向的位置开始的所有字符,直到它到达 [=15=]
终止符 - 这就是你看到内存内容的原因在 test
.
之后
因此您可以执行以下任一操作:
printf("%.*s\n", testString.n, testString.p);
(但请注意,大多数对预期 [=15=]
终止的 C 字符串进行操作的函数将不适用于此指针,除非它们也采用字符串的长度)
或将 Go 部分更改为类似这样的内容,然后在 C 端使用后 free()
指针:
func GetTestString() *C.char {
return C.CString("test") // CString will allocate string on C heap
}
所以,我尝试 运行 我的 go 代码在 C++ 项目上动态加载。它工作得很好,除了返回值上有一些不需要的字符串。正如我解释的那样,我从 Go 那里得到了一些不需要的信息。
我的代码:
package main
import "C"
func main() {}
//export GetTestString
func GetTestString() string {
return "test"
}
我用以下方法构建它:
go build -buildmode=c-shared -o test.so test.go
使用此功能将其动态加载到我的 CPP 项目中:
typedef struct { const char *p; ptrdiff_t n; } GoString;
void getTestString() {
void *handle;
char *error;
handle = dlopen ("./test.so", RTLD_LAZY);
if (!handle) {
fputs (dlerror(), stderr);
exit(1);
}
// resolve getTestString symbol and assign to fn ptr
auto getTestString = (GoString (*)())dlsym(handle, "GetTestString");
if ((error = dlerror()) != NULL) {
fputs(error, stderr);
exit(1);
}
// call GetTestString()
GoString testString = (*getTestString)();
printf("%s\n", testString.p);
// close file handle when done
dlclose(handle);
}
输出为:
"testtrue ...\n H_T= H_a= H_g= MB, W_a= and cnt= h_a= h_g= h_t= max= ptr siz= tab= top= u_a= u_g=, ..., fp:argp=falsefaultgcingpanicsleepsse41sse42ssse3 (MB)\n addr= base code= ctxt: curg= goid jobs= list= m->p= next= p->m= prev= span= varp=(...)\n, not SCHED efenceerrno objectpopcntscvg: selectsweep (scan (scan) MB in dying= locks= m->g0= nmsys= s=nil\n, goid=, size=, sys: GODEBUGIO waitSignal \ttypes \tvalue=cs fs gctracegs panic: r10 r11 r12 r13 r14 r15 r8 r9 rax rbp rbx rcx rdi rdx rflags rip rsi rsp runningsignal syscallunknownwaiting etypes goalΔ= is not mcount= minutes nalloc= newval= nfree..."
当通过指向 C 的指针传递字符串时,您需要在 GoString
中使用长度 (n
) 来获取正确数量的字符,因为 p
处的字符串不是 [=15= ]
终止。或者您可以 return *C.char
而不是 string
并使用 C.CString()
在 C 堆上分配副本(然后您负责在使用后释放)。请参阅 Cgo 文档 here。
你的代码中发生的事情是 printf()
简单地打印从 string.p
指向的位置开始的所有字符,直到它到达 [=15=]
终止符 - 这就是你看到内存内容的原因在 test
.
因此您可以执行以下任一操作:
printf("%.*s\n", testString.n, testString.p);
(但请注意,大多数对预期 [=15=]
终止的 C 字符串进行操作的函数将不适用于此指针,除非它们也采用字符串的长度)
或将 Go 部分更改为类似这样的内容,然后在 C 端使用后 free()
指针:
func GetTestString() *C.char {
return C.CString("test") // CString will allocate string on C heap
}