转换类型转换和未导出的CGo类型

时间:2012-11-23 20:35:26

标签: types type-conversion go

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

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

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

我是否正确理解完全无法在{em>其他包中的test.Test值中创建新的unsafe.Pointer实例比test

尝试使用&test.Test{ptr},其中ptrunsafe.Pointer值的内容失败,原因显而易见,在字段值中显示消息cannot use ptr (type unsafe.Pointer) as type *test._Ctype_C_Test,并且类型转换为{{1不起作用,因为不导出此类型 而且我认为让我的其他模块使用CGo并在其中重新定义相同的C结构也不起作用,因为该包具有类似*test._Ctype_C_Testclient._Ctype_C_Test需要test.Test的东西,并且它们与typechecker的观点不同。

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

更新:以下是我要强制使用的代码:https://gist.github.com/4141343

2 个答案:

答案 0 :(得分:3)

我问了一个关于golang-nuts的question并给出了一个如何做我想要的例子。它似乎现在工作。以下是Ian回答的代码:

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

答案 1 :(得分:2)

类似

foo := test.Test{}
*(unsafe.Pointer)(&foo.Field) = ptr
还测试了吗?我希望这能奏效。 (希望如此。有点。)

EDIT 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
$