英文:
Why casting interface{} to cgo types is not allowed?
问题
这更像是一个技术问题,而不是一个实际的问题。由于在cgo中我们没有可变参数函数,并且目前没有有效的解决方案,我想知道是否可以将interface{}转换为cgo类型。这样就可以实现更动态的函数。我相当确定我们甚至不能以动态方式为导出的(//export)函数的参数分配类型,也不能使用省略号。那么这些限制背后的原因是什么呢?
谢谢你的回答。
import "C"
//export Foo
func Foo(arg1, arg2, arg3) {
}
英文:
It's more of a technical question, not really an issue. Since we don't have variadic functions in cgo and there's currently no valid solution, I wonder if it'd be possible to cast interface{} to cgo types. So this would allow us to have more dynamic functions. I'm pretty sure we're not even allowed to assign types in a dynamic way to arguments in exported (//export) functions, neither the use of ellipsis is allowed. So what's the reason behind all those limits?
Thanks for answering.
import "C"
//export Foo
func Foo(arg1, arg2, arg3) {
}
答案1
得分: 2
C编译器允许但不要求使用不同的返回机制返回不同类型的结果。例如,一些C编译器可能会将float
类型的结果返回到%f0
寄存器,将double
类型的结果返回到%f0:f1
寄存器对中,将整数结果返回到%d0
寄存器,将指针结果返回到%a0
寄存器。
对于为Go编写Cgo接口的人来说,这意味着他们必须以不同的方式处理每种类型的C函数。换句话说,不可能写成:
generic_type Cfunc(ctype1 arg1, ctype2 arg2) { ... }
我们必须在编译时知道Cfunc
返回的是float/double/<some-integer-type>/<some-pointer-type>,以便我们可以获取正确的寄存器并将其(或它们)的值放入Cgo返回值槽中,Cgo接口可以获取并封装它以供在Go中使用。
对于作为调用C函数的Cgo包装器的Go编译器的用户来说,这意味着你必须知道正确的类型。这里没有通用的答案;在这里无法使用interface{}
。你必须将确切、正确的类型传达给Cgo层,以便Cgo层可以使用该确切、正确的类型信息在编译时生成正确的机器代码。
如果C编译器的编写者有一种方式可以标记他们的代码,以便在链接时,链接器可以引入正确的“将正确的寄存器保存到内存”位置,那么Cgo包装器的作者就可以使用链接器在链接时自动找到C函数的类型。但是这些C编译器没有向链接器提供这种能力。
你使用的特定编译器是否属于这些编译器之一?我们不知道,因为你没有提到。但是:
> 我相当确定我们甚至不被允许在导出的(//export)函数中以动态方式为参数分配类型,也不允许使用省略号。那么这些限制背后的原因是什么呢?
这是正确的,上面稍微理论化的例子就是一个原因。(我构造这个例子时混合了68k C编译器和SPARC C编译器的实际技术,所以我认为没有单个的C编译器是这样的。但是过去确实存在这样的例子,而且SPARC系统仍然将整数返回到%o0,或者在V8 SPARC上返回到%o0+%o1,而将浮点数返回到%f0或%f0+%f1。)
英文:
C compilers are allowed, but not required, to return different types using different return mechanisms. For instance, some C compilers might return float
results in the %f0
register, double
results in the %f0:f1
register pair, integer results in the %d0
register, and pointer results in the %a0
register.
What this means for the person writing the Cgo interface for Go is that they must, in general, handle each kind of these C functions differently. In other words, it's not possible to write:
generic_type Cfunc(ctype1 arg1, ctype2 arg2) { ... }
We must know, at compile time, that Cfunc
returns float/double/<some-integer-type>/<some-pointer-type> so that we can grab the correct register(s) and stuff its (or their) value(s) into the Cgo return-value slot, where the Cgo interface can get it and wrap it up for use in Go.
What this means for you, as a user of a Go compiler that implements Cgo wrappers to call C functions, is that you have to know the right type. There is no generalized answer; there is no way to use interface{}
here. You must communicate the exact, correct type to the Cgo layer, so that the Cgo layer can use that exact, correct type information to generate the correct machine code at compile time.
If the C compiler writers had some way of flagging their code so that, e.g., at link time, the linker could pull in the right "save correct register to memory" location, that would enable the Cgo wrapper author to use the linker to automagically find the C function's type at link time. But these C compilers don't offer this ability to the linkers.
Is your particular compiler one of these? We don't know: you didn't say. But:
> I'm pretty sure we're not even allowed to assign types in a dynamic way to arguments in exported (//export) functions, neither the use of ellipsis is allowed. So what's the reason behind all those limits?
That's correct, and the (slightly theoretical) example above is a reason. (I constructed this example by mixing actual techniques from 68k C compilers and SPARC C compilers, so I don't think there's any single C compiler like this. But examples like this did exist in the past, and SPARC systems still return integers in %o0, or %o0+%o1 on V8 SPARC, vs floating point in %f0 or %f0+%f1.)
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论