英文:
Go type conversions and unexported CGo types
问题
假设有一个CGo包,其中定义了一个如下所示的结构体:
package test
...
type Test struct {
Field *C.C_Test
}
...
现在假设我从其他地方得到了一个我知道指向C_Test
C结构体的unsafe.Pointer
。
我理解得对吗,即在一个不同于test
包的包中,没有完全的方法可以使用unsafe.Pointer
值创建新的test.Test
实例?
尝试使用类似&test.Test{ptr}
的东西,其中ptr
是unsafe.Pointer
值,由于明显的原因而失败,出现消息cannot use ptr (type unsafe.Pointer) as type *test._Ctype_C_Test
in field value,并且类型转换为*test._Ctype_C_Test
也不起作用,因为此类型未导出。
而且我认为,让我的其他模块使用CGo并在其中重新定义相同的C结构体也行不通,因为该包将具有类似于client._Ctype_C_Test
的内容,但test.Test
需要test._Ctype_C_Test
,从类型检查器的角度来看,它们是不同的。
一些背景: 当我使用go-gtk
库的GtkBuilder
时,我需要一种创建这样的结构体的方法。
它的GtkBuilder.GetObject(name)
方法返回*GObject
指针,该指针又包含了我需要以某种方式转换为gtk.GtkEntry
结构体的unsafe.Pointer
字段。gtk.GtkEntry
本身包含了类型为gtk.GtkWidget
的隐式字段,该字段具有类型为*C.GtkWidget
的显式字段,因此我需要将unsafe.Pointer
转换为*C.GtkWidget
,但是我不能,正如我在上面的简单示例中所描述的那样。
更新: 这是我试图使其工作的代码:https://gist.github.com/4141343
英文:
Suppose there is CGo package with a struct defined like this:
package test
...
type Test struct {
Field *C.C_Test
}
...
Now suppose that from somewhere else I get unsafe.Pointer
which I know points to C_Test
C structure.
Do I understand correctly that there is completely no way to create new test.Test
instance from the unsafe.Pointer
value while being in a package other than test
?
Attempting to use something like &test.Test{ptr}
, where ptr
is unsafe.Pointer
value, fails for obvious reasons with message cannot use ptr (type unsafe.Pointer) as type *test._Ctype_C_Test
in field value, and type conversion to *test._Ctype_C_Test
does not work as well because this type is not exported.
And I think that making my other module to use CGo and redefining the same C structure in it will not work either since that package will have something like client._Ctype_C_Test
but test.Test
requires test._Ctype_C_Test
, and they are different from the point of view of the typechecker.
Some background: I need a way to create such structure when I use GtkBuilder
with go-gtk
library.
Its GtkBuilder.GetObject(name)
method returns *GObject
pointer which in turn contains unsafe.Pointer
field which I need to turn somehow into, say, gtk.GtkEntry
struct. gtk.GtkEntry
itself contains implicit field of type gtk.GtkWidget
which has explicit field of type *C.GtkWidget
, so I need to convert unsafe.Pointer
to *C.GtkWidget
, but I cannot, as I have described in the simple example above.
Update: here is the code I'm trying to force to work: https://gist.github.com/4141343
答案1
得分: 3
我在golang-nuts上提了一个问题,并得到了一个关于如何实现我想要的功能的示例。现在似乎可以工作了。以下是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,因为像这样的技巧很痛苦),但这与问题无关。
英文:
I asked a question on golang-nuts and was given an example on how to do what I want. It seems to work now. Here is the code from Ian's answer:
var t test.Test
p := (*unsafe.Pointer)(unsafe.Pointer(&t.Field))
*p = unsafe.Pointer(u)
So, all what was needed is double cast to unsafe.Pointer
and then to *unsafe.Pointer
. I came up with the following code to simplify the assign process:
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))
}
Then, however, I decided to abstain from using GTK, since it is painful to do tricks like this) but this is not related to the question.
答案2
得分: 2
是这样测试的吗?
foo := test.Test{}
*(unsafe.Pointer)(&foo.Field) = ptr
我希望这样能够工作。(希望如此。)
英文:
Was something like
foo := test.Test{}
*(unsafe.Pointer)(&foo.Field) = ptr
also tested? I would expect that to work. (Hope so. Kinda.)
EDIT 2012-11-24 13:42 UTC: 2nd attempt
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
$
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论