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

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

golang: can i share C.int between packages

问题

在主包中,我有:

  1. var foo C.int
  2. foo = 3
  3. t := fastergo.Ctuner_new()
  4. fastergo.Ctuner_register_parameter(t, &foo, 0, 100, 1)

在fastergo包中,我有:

  1. func Ctuner_register_parameter(tuner unsafe.Pointer, parameter *C.int, from C.int, to C.int, step C.int) C.int {
  2. ...
  3. }

如果我尝试运行它,我会得到以下错误:

  1. 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:

  1. var foo C.int
  2. foo = 3
  3. t := fastergo.Ctuner_new()
  4. fastergo.Ctuner_register_parameter(t, &foo, 0, 100, 1)

in the fastergo package i have:

  1. func Ctuner_register_parameter(tuner unsafe.Pointer, parameter *C.int, from C.int, to C.int, step C.int) C.int {
  2. ...
  3. }

if i try to run it, i get:

  1. 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类型。包装器包应该隐藏所有实现细节。

您没有提供足够的信息,以便我们创建可以编译和运行的示例代码。以下是我期望看到的大致概述:

  1. package main
  2. import "tuner"
  3. func main() {
  4. var foo int
  5. foo = 3
  6. t := tuner.New()
  7. t.RegisterParameter(&foo, 0, 100, 1)
  8. }

.

  1. package tuner
  2. import (
  3. "unsafe"
  4. )
  5. /*
  6. #include "ctuner.h"
  7. */
  8. import "C"
  9. type Tuner struct {
  10. ctuner uintptr
  11. }
  12. func New() *Tuner {
  13. var t Tuner
  14. t.ctuner = uintptr(unsafe.Pointer(C.ctuner_new()))
  15. return &t
  16. }
  17. func (t *Tuner) RegisterParameter(parameter *int, from, to, step int) error {
  18. var rv C.int
  19. rv = C.ctuner_register_parameter(
  20. (*C.ctuner)(unsafe.Pointer(t.ctuner)),
  21. (*C.int)(unsafe.Pointer(parameter)),
  22. C.int(from),
  23. C.int(to),
  24. C.int(step),
  25. )
  26. if rv != 0 {
  27. // 处理错误
  28. }
  29. return nil
  30. }
英文:

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:

  1. package main
  2. import "tuner"
  3. func main() {
  4. var foo int
  5. foo = 3
  6. t := tuner.New()
  7. t.RegisterParameter(&foo, 0, 100, 1)
  8. }

.

  1. package tuner
  2. import (
  3. "unsafe"
  4. )
  5. /*
  6. #include "ctuner.h"
  7. */
  8. import "C"
  9. type Tuner struct {
  10. ctuner uintptr
  11. }
  12. func New() *Tuner {
  13. var t Tuner
  14. t.ctuner = uintptr(unsafe.Pointer(C.ctuner_new()))
  15. return &t
  16. }
  17. func (t *Tuner) RegisterParameter(parameter *int, from, to, step int) error {
  18. var rv C.int
  19. rv = C.ctuner_register_parameter(
  20. (*C.ctuner)(unsafe.Pointer(t.ctuner)),
  21. (*C.int)(unsafe.Pointer(parameter)),
  22. C.int(from),
  23. C.int(to),
  24. C.int(step),
  25. )
  26. if rv != 0 {
  27. // handle error
  28. }
  29. return nil
  30. }

答案2

得分: 0

根据peterSO的解释,你不能在包之间传递C.int。但是,你可以通过转换指针类型在包之间传递指针。为此,你需要在目标包中定义一个命名类型,将该类型导入到调用包中,并通过unsafe.Pointer进行转换。对于单个int来说,这样做没有任何意义。

但是,如果你将转换复杂类型的代码保留在一个包中,这将非常有帮助;例如,一个字符串数组(或任何类型的嵌套数组)。

下面的示例是将Go函数导出为在C中调用,但是这也可以反过来使用,即如果你想调用返回嵌套数组的C函数。

  1. package convert
  2. import "C"
  3. type PP_char **C.char
  4. func From_c_to_go(arr_str PP_char, length int) []string {
  5. // 对C类型进行一些操作
  6. var slice []string
  7. for _, s := range unsafe.Slice(arr_str, length) {
  8. if s == nil {
  9. break
  10. }
  11. x := C.GoString(s)
  12. slice = append(slice, x)
  13. }
  14. return slice
  15. }
  1. package main
  2. import "C"
  3. import "convert"
  4. //export myFunc
  5. func myFunc(arr_str **C.char, length int){
  6. retyped_arr_str := convert.PP_char(unsafe.Pointer(arr_str))
  7. slice := convert.From_c_to_go(retyped_arr_str, length)
  8. // 对slice进行一些操作
  9. }

你也可以决定将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.

  1. package convert
  2. import "C"
  3. type PP_char **C.char
  4. func From_c_to_go(arr_str PP_char, length int) []string {
  5. // Some operation on the Ctype
  6. var slice []string
  7. for _, s := range unsafe.Slice(arr_str, length) {
  8. if s == nil {
  9. break
  10. }
  11. x := C.GoString(s)
  12. slice = append(slice, x)
  13. }
  14. return slice
  15. }
  1. package main
  2. import "C"
  3. import "convert"
  4. //export myFunc
  5. func myFunc(arr_str **C.char, length int){
  6. retyped_arr_str := convert.PP_char(unsafe.Pointer(arr_str))
  7. slice := convert.From_c_to_go(retyped_arr_str, length)
  8. // Do something with slice
  9. }

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:

确定