英文:
Unknown string from Dynamic Loaded Golang to CPP
问题
所以,我尝试在C++项目中使用动态加载运行我的Go代码。它工作得很好,除了返回值中有一些不需要的字符串。如下所述,我从Go中获取了一些不需要的信息。
我的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);
}
// 解析getTestString符号并分配给函数指针
auto getTestString = (GoString (*)())dlsym(handle, "GetTestString");
if ((error = dlerror()) != NULL) {
fputs(error, stderr);
exit(1);
}
// 调用GetTestString()
GoString testString = (*getTestString)();
printf("%s\n", testString.p);
// 完成后关闭文件句柄
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..."
英文:
So, I tried to run my go code on C++ project with dynamic loading. It's working great, except there is some unwanted string on returned value. As I explained down, I got some information from Go that unwanted.
My go code:
package main
import "C"
func main() {}
//export GetTestString
func GetTestString() string {
return "test"
}
I build it with:
go build -buildmode=c-shared -o test.so test.go
Dynamically load it on my CPP project with this function:
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);
}
Output is:
>"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..."
答案1
得分: 1
在通过指针传递字符串到 C 时,你需要使用 GoString
中的长度 (n
) 来获取正确数量的字符,因为指向 p
的字符串不是以 \0
结尾的。或者你可以返回 *C.char
而不是 string
,并使用 C.CString()
在 C 堆上分配副本(然后在使用后负责释放)。请参阅 Cgo 文档 这里。
在你的代码中发生的情况是,printf()
简单地从 string.p
指向的位置开始打印所有字符,直到遇到 \0
终止符为止 - 这就是为什么你看到了 test
之后的内存内容。
所以你可以这样做:
printf("%.*s\n", testString.n, testString.p);
(但请注意,大多数操作预期为以 \0
结尾的 C 字符串的函数在这个指针上将无法工作,除非它们还接受字符串的长度)
或者将 Go 部分更改为以下内容,然后在 C 端使用后释放指针:
func GetTestString() *C.char {
return C.CString("test") // CString 将在 C 堆上分配字符串
}
英文:
When passing strings via pointer to C you need either use length (n
) in GoString
to fetch right number of characters as string at p
is not \0
terminated. Or you can return *C.char
instead of string
and use C.CString()
to allocate copy on C heap (which you then are responsible for freeing after use). See Cgo documentation here.
What is happening in your code is that printf()
simply prints all characters starting from location pointed to by string.p
until it hits \0
terminator - that's why you see contents of memory after test
.
So you can do either something like:
printf("%.*s\n", testString.n, testString.p);
(but note that most functions that operate on C strings which are expected to be \0
terminated will not work on this pointer unless they also take length of string)
or change Go part to something like this and then free()
pointer after use on C side:
func GetTestString() *C.char {
return C.CString("test") // CString will allocate string on C heap
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论