2

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

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

现在假设我从其他地方得到unsafe.Pointer的我知道指向C_TestC 结构。

我是否正确理解在除 之外的包中完全没有办法从值创建新test.Test实例?unsafe.Pointertest

尝试使用类似&test.Test{ptr}, where ptris unsafe.Pointervalue 之类的东西,由于字段值中的消息显而易见的原因而失败cannot use ptr (type unsafe.Pointer) as type *test._Ctype_C_Test,并且类型转换为*test._Ctype_C_Test也无法正常工作,因为此类型未导出。
而且我认为让我的另一个模块使用 CGo 并在其中重新定义相同的 C 结构也不起作用,因为该包将具有类似client._Ctype_C_Testtest.Testrequires的内容test._Ctype_C_Test,并且从类型检查器的角度来看它们是不同的。

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

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

4

2 回答 2

3

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

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,因为这样做很痛苦)但这与问题无关。

于 2012-11-29T19:42:23.920 回答
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
$ 
于 2012-11-23T21:05:11.723 回答