【发布时间】:2018-01-10 21:50:42
【问题描述】:
我已经解决了我在使用 swig 包装一些 C 代码以使用 golang 时遇到的问题,但问题并不在于 swig。
我可以传入一个基本字符串切片,但只要我用基本字符串以外的任何内容构造切片,我就会出现恐慌:运行时错误:cgo 参数具有指向 Go 指针的 Go 指针。
go version go1.8.5 linux/amd64
这是示例代码及其输出
package main
import (
"fmt"
"reflect"
"unsafe"
)
/*
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct { char *p; int n; } _gostring_;
typedef struct { void* array; int len; int cap; } _goslice_;
void prtText(char * const *txt, int len)
{
int i = 0;
for ( i=0; i<len; i++ ) {
printf("Text %d is: %s\n", i, txt[i]);
}
}
void _wrap_printText(_goslice_ _swig_go_0) {
_gostring_ *p;
char **arg1 = (char **)calloc(_swig_go_0.len, sizeof(char*));
if (arg1) {
for (int i=0; i<_swig_go_0.len; i++) {
p = &(((_gostring_*)_swig_go_0.array)[i]);
arg1[i] = calloc(1,(p->n)+1);
strncpy(arg1[i], p->p, p->n);
}
}
int arg2 = _swig_go_0.len;
prtText((char *const *)arg1,arg2);
}
*/
import "C"
func PrintText(arg1 []string) {
C._wrap_printText(*(*C._goslice_)(unsafe.Pointer(&arg1)))
}
func main() {
s := []string{}
s = append(s, "blah")
s = append(s, "hello")
s = append(s, "again")
ns := []string{}
ns = append(ns, "ns: "+s[0])
ns = append(ns, "ns: "+s[1])
ns = append(ns, "ns: "+s[2])
fmt.Println("type s:", reflect.TypeOf(s))
fmt.Println("type ns:", reflect.TypeOf(ns))
fmt.Println("s:", s)
fmt.Println("ns:", ns)
PrintText(s)
PrintText(ns)
}
go build -i -x -gcflags '-N -l' main.go
./main
type s: []string
type ns: []string
s: [blah hello again]
ns: [ns: blah ns: hello ns: again]
Text 0 is: blah
Text 1 is: hello
Text 2 is: again
panic: runtime error: cgo argument has Go pointer to Go pointer
如您所见,第一个字符串切片工作正常,但只要我执行基本字符串以外的任何操作,它就会失败。我尝试在将新字符串附加到切片之前先创建新字符串,但问题仍然存在。
我做错了什么?
【问题讨论】:
-
您故意绕过任何安全检查。您需要先正确转换您的
[]string。查看stackoverflow.com/questions/45997786/…的答案 -
运行时出现恐慌,因为不允许将指针传递给 Go 分配的内存。虽然 GC 还没有移动内存,但它很容易收集一个超出范围的值,因为它被传递给 C 函数。