我见过一个原型为:
的函数int myfunc(void** ppt)
此函数在C文件中调用为 a = myfunc(mystruct ** var1);
其中mystruct是我们拥有的结构之一的typedef。
这在MSVC6.0中没有任何编译错误,但是当我用其他C编译器编译它时,它会在调用此函数的地方出错,并显示错误消息:
类型为mystruct **的参数与void **
类型的参数不兼容myfunc()的参数保持为void **,因为它似乎是一个通用的malloc类函数,可以使用各种结构变量类型进行内存分配
mystruct**
,但它不起作用] -AD
答案 0 :(得分:22)
comp.lang.c FAQ在Question 4.9中详细说明了此问题。简而言之,他们说它不是严格的可移植性来向void **
投射任意指向指针的指针;他们接着解释说“像这样的代码可能有用,有时也会被推荐,但它依赖于具有相同内部表示的所有指针类型(这是常见的,但不是通用的)。”他们接着解释说“你玩的任何void **
值必须是某个地方实际void *
值的地址;像(void **)&dp
这样的转换,虽然它们可能会关闭编译器,但是不可移植(甚至可能不会做你想要的)。“
因此,您可以安全/可移植地使用以下代码实现所需的行为:
some_type *var1 = foo();
void *tmp_void_ptr = (void *)var1;
myfunc(&tmp_void_ptr);
答案 1 :(得分:8)
void**
有效,但根据您的错误消息,您可能必须按如下方式显式转换参数:
mystruct **var1;
x = myfunc ((void**) var1);
那是因为myfunc
函数期待void**
类型。虽然void*
可以隐式地转换为任何其他指针,但对于双指针则不然 - 你需要显式地转换它。
答案 2 :(得分:3)
编译器无法自动从mystruct**
投射到void**
。
请考虑以下代码:
void stupid(struct mystruct **a, struct myotherstruct **b)
{
void **x = (void **)a;
*x = *b;
}
编译器不会抱怨myotherstruct*
行中从void*
到*x = *b
的隐式强制转换,即使该行试图将指针指向myotherstruct
在一个只能放置mystruct
指针的地方。
错误实际上是在上一行中,它将“指向mystruct
指针的地方的指针”转换为指向指向任何东西的地方的指针可以放“。 这个是没有隐式演员的原因。当然,当您使用显式强制转换时,编译器会假定您知道自己在做什么。
答案 3 :(得分:1)
这个问题有点令人困惑。但是,void **
肯定是合法且有效的C,并且意味着“指向void
的指针”。
我不确定你的调用示例,参数(“mystruct ** var1”)没有意义。如果var1
的类型为mystruct **
,则调用只应为a = func(var1);
,这可能是一个错字。
转换应该有效,但你需要转换为void **
,因为这是函数所期望的。
答案 4 :(得分:0)
尽管看起来很脏但有时候如果不使用void **就无法解决问题。
答案 5 :(得分:0)
是的,void **
完全可以接受,在某些情况下非常有用。同时考虑到声明void **foo
和void *bar
,编译器将知道foo指向的对象的大小(它指向一个指针,所有指针都是相同的大小,除了一些古代您不必担心的平台),但它不知道bar指向的对象的大小(它可能指向任何大小的对象)。因此,您可以安全地对void **
指针执行指针运算,但在void *
指针上不。您必须先将它们转换为其他内容,例如char *
。 GCC将允许您假装void *
和char *
是等效的,每个对象指向一个字节大小的对象,但这是非标准且不可移植的。