【问题标题】:Go type conversions and unexported CGo typesGo 类型转换和未导出的 CGo 类型
【发布时间】:2012-11-12 04:37:40
【问题描述】:

假设有一个 CGo 包,其结构定义如下:

package test
...
type Test struct {
    Field *C.C_Test
}
...

现在假设我从其他地方得到unsafe.Pointer,我知道它指向C_Test C 结构。

我是否理解正确完全没有办法从unsafe.Pointer 值创建新的test.Test 实例,而在包中其他而不是test ?

尝试使用&test.Test{ptr} 之类的东西,其中ptrunsafe.Pointer 值,由于字段值中出现消息cannot use ptr (type unsafe.Pointer) as type *test._Ctype_C_Test 的明显原因而失败,并且类型转换为*test._Ctype_C_Test 不能正常工作,因为这种类型未导出。
而且我认为让我的另一个模块使用 CGo 并在其中重新定义相同的 C 结构也不起作用,因为该包将具有类似 client._Ctype_C_Testtest.Test 需要 test._Ctype_C_Test 的内容,它们与类型检查器的视图。

一些背景知识:当我将GtkBuildergo-gtk 库一起使用时,我需要一种方法来创建这样的结构。
它的GtkBuilder.GetObject(name) 方法返回*GObject 指针,该指针又包含unsafe.Pointer 字段,我需要以某种方式将其转换为gtk.GtkEntry 结构。 gtk.GtkEntry 本身包含 gtk.GtkWidget 类型的隐式字段,它具有 *C.GtkWidget 类型的显式字段,所以我需要将 unsafe.Pointer 转换为 *C.GtkWidget,但我不能,正如我在上面的简单示例中描述的那样。

更新:这是我试图强制工作的代码:https://gist.github.com/4141343

【问题讨论】:

    标签: types type-conversion go


    【解决方案1】:

    我在 golang-nuts 上询问了question,并获得了一个关于如何做我想做的事的例子。它现在似乎起作用了。这是伊恩回答的代码:

    var t test.Test
    p := (*unsafe.Pointer)(unsafe.Pointer(&t.Field))
    *p = unsafe.Pointer(u)
    

    所以,所有需要的只是双重转换为unsafe.Pointer,然后转换为*unsafe.Pointer。我想出了以下代码来简化分配过程:

    func Assign(to unsafe.Pointer, from unsafe.Pointer) {
        fptr := (*unsafe.Pointer)(from)
        tptr := (*unsafe.Pointer)(to)
        *tptr = *fptr
    }
    
    func Init(builder *gtk.GtkBuilder) {
        messageNameEntryWidget := gtk.GtkWidget{}
        Assign(unsafe.Pointer(&messageNameEntryWidget.Widget),
               unsafe.Pointer(&builder.GetObject("messageNameEntry").Object))
    }
    

    然后,然而,我决定放弃使用 GTK,因为这样做很痛苦)但这与问题无关。

    【讨论】:

      【解决方案2】:

      有点像

      foo := test.Test{}
      *(unsafe.Pointer)(&foo.Field) = ptr
      

      也测试过?我希望这能奏效。 (希望如此。有点。)

      编辑 2012-11-24 13:42 UTC:第二次尝试

      package main
      
      /*
      
      #include <stdio.h>
      #include <stdlib.h>
      
      typedef struct {
              int foo;
              char *bar;
      } Test_t;
      
      void test_dump(Test_t *test) {
              printf(".foo %d, .bar %s\n", test->foo, test->bar);
      }
      
      void *test_new(int foo, char *bar) {
              Test_t *p = malloc(sizeof(Test_t));
              p->foo = foo;
              p->bar = bar;
              return p;
      }
      
      */
      import "C"
      
      import "unsafe"
      
      type Test struct {
              Field *C.Test_t
      }
      
      func main() {
              hello := C.CString("Hello")
              defer C.free(unsafe.Pointer(hello))
              test := &Test{(*C.Test_t)(C.test_new(42, hello))}
              C.test_dump(test.Field)
      }
      

      $ go clean && go build && ls
      main.go  13535422
      $ ./13535422 
      .foo 42, .bar Hello
      $ 
      

      【讨论】:

      • 不,很遗憾,这不起作用。就例子而言,我得到了invalid indirect of unsafe.Pointer(&amp;foo.Field) (type unsafe.Pointer)
      • 是的,您的代码可以工作,因为 C 结构定义与不安全指针转换尝试在同一个包中。我在回答中写了这个。尝试将 main 函数移动到单独的包中,你会明白我的意思。我将很快添加示例代码。
      • 对不起,我的意思是“问题”而不是“答案”:)
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多