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