golang:我可以在包之间共享C.int吗?

huangapple go评论71阅读模式
英文:

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.

huangapple
  • 本文由 发表于 2013年7月26日 19:17:56
  • 转载请务必保留本文链接:https://go.coder-hub.com/17879961.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定