尽管涉及类型为 C.void
的值的错误数量众多,但 cgo
仍未能拒绝以下程序。(“void”一词本身意味着“空”,因此对于类型“void”来说,包含一个值是毫无意义的!)
我不确定在多大程度上可以解决这个问题,考虑到修复 #3729 的方法添加了一个测试,以验证 Go 调用者可以将 _, err
绑定到对返回 void 的函数的调用结果。
package p
/*
static void return_void() { return; }
*/
import "C"
func F() {
x := C.return_void() // ERROR HERE
var y C.void = x // ERROR HERE
var z *C.void = &y // ERROR HERE
var b [0]byte = *z // ERROR HERE
_ = b
}
9条答案
按热度按时间58wvjzkj1#
https://golang.org/cl/63830提到了这个问题:
cmd/cgo: use a named type to indicate syntactic context
1zmg4dgp2#
https://golang.org/cl/63831提到了这个问题:
cmd/cgo: do not instantiate C.void
ct3nt3jp3#
以下是一些关于这个问题的更多示例:
C.void
是一个返回类型时将其Map到一个值,但在它是一个参数类型时却没有这样做:今天的错误:
unsafe.Pointer
与*C.void
不匹配,尽管我们将返回void*
的函数Map为返回unsafe.Pointer
。今天的错误:
*C.void
,这个程序应该是正确的:但今天它无法编译:
f45qwnt84#
问题的根本在于,我们将
C.void
当作一个完整的、可示例化的类型来对待,但实际上并非如此。这意味着我们目前将void*
翻译成两种不同的 Go 类型:当void*
出现在 C 代码中时,我们将其翻译为unsafe.Pointer
,但当它出现在 Go 代码中时,我们将其翻译为*_Ctype_void
。@hirochachacha 指出,我们可以通过 cgo 命令在
*C.void
每次出现时重写为unsafe.Pointer
,类似于我为 #19487 中的其他不完整类型所做的建议,但如果我们不 也消除C.void
本身,我们仍然会为上面第二个示例产生令人困惑的错误信息。z4bn682m5#
我迄今为止找到的唯一一个实际使用
*C.void
的代码是这个文件,作者是 @paulsmith:它是一个机械生成的 Package 器,错误地 Package 的
*C.void
函数似乎实际上并没有被调用。(但我要指出的是,在 GitHub 上搜索C.void
受到了极大的阻碍,因为 GitHub 坚持忽略查询字符串中的所有点。)q5lcpyga6#
作为另一个参考点,字符串
C.void
不在 Go Corpus v0.01 的任何源代码中出现。d5vmydt97#
“void”这个词本身意味着“空”,所以类型“void”包含一个值是没有意义的!
问题的根本在于,我们把
C.void
当作一个完整的、可示例化的类型来对待,但实际上它并不是。只是好奇,将
void
视为等同于Go语言中的struct{}
(空结构体)是否正确?虽然空结构体不能包含任何值,但它仍然是一个真实的类型,可以被示例化和赋值。那么void
与此不同吗?lbsnaicq8#
虽然空结构体不能包含任何值,但它仍然是一个真实的类型,可以示例化和赋值。那么
void
与void
有什么不同呢?void
是不同的。请参阅C11规范的第6.3.2.2节:“一个 void表达式 (具有
void
类型的表达式)的(不存在的)值不应以任何方式使用,且不应对此类表达式应用隐式或显式转换(除非转换为void
)。”然而,请注意,Go类型
struct{}
没有对应的C类型:“当......结构体或联合体被定义为不包含命名成员、无匿名结构和无匿名联合时,行为是未定义的(6.7.2.1)。”相反,Go类型
struct{}
恰好有一个值,表示为struct{}{}
。它可以显式转换为具有struct{}
作为其底层类型的其他类型,并且在存储在interface{}
类型的变量中时,可以与nil
区分开来。e5njpo689#
(但也参见#20275(评论):在Go中具有不可示例化的
unsafe.Void
类型可能会允许更好地 Package 带有不完整类型的尾随成员的C结构体。)