英文:
golang: can i share C.int between packages
问题
在主包中,我有:
var foo C.int
foo = 3
t := fastergo.Ctuner_new()
fastergo.Ctuner_register_parameter(t, &foo, 0, 100, 1)
在fastergo包中,我有:
func Ctuner_register_parameter(tuner unsafe.Pointer, parameter *C.int, from C.int, to C.int, step C.int) C.int {
...
}
如果我尝试运行它,我会得到以下错误:
demo.go:14[/tmp/go-build742221968/command-line-arguments/_obj/demo.cgo1.go:21]: cannot use &foo (type *_Ctype_int) as type *fastergo._Ctype_int in function argument
我不太确定Go在这里试图告诉我什么,但我有种感觉它想告诉我,所有的C.int并不相等?为什么会这样?我该如何解决这个问题或绕过它?
英文:
in the main package i have:
var foo C.int
foo = 3
t := fastergo.Ctuner_new()
fastergo.Ctuner_register_parameter(t, &foo, 0, 100, 1)
in the fastergo package i have:
func Ctuner_register_parameter(tuner unsafe.Pointer, parameter *C.int, from C.int, to C.int, step C.int) C.int {
...
}
if i try to run it, i get:
demo.go:14[/tmp/go-build742221968/command-line-arguments/_obj/demo.cgo1.go:21]: cannot use &foo (type *_Ctype_int) as type *fastergo._Ctype_int in function argument
i am not really sure what go is trying to tell me here, but somehow i think it wants to tell me, that all C.int are not equal? why is this the case? how can i solve this / work around?
答案1
得分: 5
由于_Ctype_int
不以Unicode大写字母开头,该类型是包内部的。在C包装器包中使用Go类型,将它们转换为C类型。包装器包应该隐藏所有实现细节。
您没有提供足够的信息,以便我们创建可以编译和运行的示例代码。以下是我期望看到的大致概述:
package main
import "tuner"
func main() {
var foo int
foo = 3
t := tuner.New()
t.RegisterParameter(&foo, 0, 100, 1)
}
.
package tuner
import (
"unsafe"
)
/*
#include "ctuner.h"
*/
import "C"
type Tuner struct {
ctuner uintptr
}
func New() *Tuner {
var t Tuner
t.ctuner = uintptr(unsafe.Pointer(C.ctuner_new()))
return &t
}
func (t *Tuner) RegisterParameter(parameter *int, from, to, step int) error {
var rv C.int
rv = C.ctuner_register_parameter(
(*C.ctuner)(unsafe.Pointer(t.ctuner)),
(*C.int)(unsafe.Pointer(parameter)),
C.int(from),
C.int(to),
C.int(step),
)
if rv != 0 {
// 处理错误
}
return nil
}
英文:
Since _Ctype_int
doesn't begin with a Unicode upper case letter, the type is local to the package. Use Go types, except in the C wrapper package where you convert them to C types. The wrapper package should hide all the implementation details.
You don't provide sufficient information for us to create sample code which compiles and runs. Here's a rough outline of what I expected to see:
package main
import "tuner"
func main() {
var foo int
foo = 3
t := tuner.New()
t.RegisterParameter(&foo, 0, 100, 1)
}
.
package tuner
import (
"unsafe"
)
/*
#include "ctuner.h"
*/
import "C"
type Tuner struct {
ctuner uintptr
}
func New() *Tuner {
var t Tuner
t.ctuner = uintptr(unsafe.Pointer(C.ctuner_new()))
return &t
}
func (t *Tuner) RegisterParameter(parameter *int, from, to, step int) error {
var rv C.int
rv = C.ctuner_register_parameter(
(*C.ctuner)(unsafe.Pointer(t.ctuner)),
(*C.int)(unsafe.Pointer(parameter)),
C.int(from),
C.int(to),
C.int(step),
)
if rv != 0 {
// handle error
}
return nil
}
答案2
得分: 0
根据peterSO的解释,你不能在包之间传递C.int
。但是,你可以通过转换指针类型在包之间传递指针。为此,你需要在目标包中定义一个命名类型,将该类型导入到调用包中,并通过unsafe.Pointer
进行转换。对于单个int来说,这样做没有任何意义。
但是,如果你将转换复杂类型的代码保留在一个包中,这将非常有帮助;例如,一个字符串数组(或任何类型的嵌套数组)。
下面的示例是将Go函数导出为在C中调用,但是这也可以反过来使用,即如果你想调用返回嵌套数组的C函数。
package convert
import "C"
type PP_char **C.char
func From_c_to_go(arr_str PP_char, length int) []string {
// 对C类型进行一些操作
var slice []string
for _, s := range unsafe.Slice(arr_str, length) {
if s == nil {
break
}
x := C.GoString(s)
slice = append(slice, x)
}
return slice
}
package main
import "C"
import "convert"
//export myFunc
func myFunc(arr_str **C.char, length int){
retyped_arr_str := convert.PP_char(unsafe.Pointer(arr_str))
slice := convert.From_c_to_go(retyped_arr_str, length)
// 对slice进行一些操作
}
你也可以决定将unsafe.Pointer
的实例作为参数传递给目标包中的go函数,并在该函数中执行类型转换。
英文:
As explained by peterSO, you can't pass C.int
between packages. However, you can pass pointers between packages by converting the pointer type. To do this, you would define a named type in the target package, import that type into the calling package and covert via unsafe.Pointer
. There isn't any point in doing this with a single int.
However, it is helpful if you keep code to convert complex types in a package; for example an array of strings (or any sort of nested array).
The example below is for exporting a go function to be called in C, but this works in reverse, ie. if you want to call a C functions which a returns nested array.
package convert
import "C"
type PP_char **C.char
func From_c_to_go(arr_str PP_char, length int) []string {
// Some operation on the Ctype
var slice []string
for _, s := range unsafe.Slice(arr_str, length) {
if s == nil {
break
}
x := C.GoString(s)
slice = append(slice, x)
}
return slice
}
package main
import "C"
import "convert"
//export myFunc
func myFunc(arr_str **C.char, length int){
retyped_arr_str := convert.PP_char(unsafe.Pointer(arr_str))
slice := convert.From_c_to_go(retyped_arr_str, length)
// Do something with slice
}
You could instead decide to pass instance of unsafe.Pointer
as an argument to the go function in the target package and perform the type conversion in that function.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论