void**在ANSI-C中是可接受的类型吗?
我见过一个函数,其原型是:void**在ANSI-C中是可接受的类型吗?,c,void,C,Void,我见过一个函数,其原型是: int myfunc(void** ppt) 此函数在C文件中被称为 a=myfunc(mystruct**var1) 其中mystruct是一个结构的typedef 这在MSVC6.0中没有任何编译错误,但当我使用其他C编译器编译它时,它会在调用此函数的位置发出错误消息: mystruct**类型的参数与void**类型的参数不兼容 myfunc()的参数保留为void**,因为它似乎是一种通用的malloc类型的函数,可以使用各种结构变量类型调用,以进行内存分配
int myfunc(void** ppt)
此函数在C文件中被称为
a=myfunc(mystruct**var1)
其中mystruct是一个结构的typedef
这在MSVC6.0中没有任何编译错误,但当我使用其他C编译器编译它时,它会在调用此函数的位置发出错误消息:
mystruct**类型的参数与void**类型的参数不兼容
myfunc()的参数保留为void**,因为它似乎是一种通用的malloc类型的函数,可以使用各种结构变量类型调用,以进行内存分配
mystruct**
,但没有成功]void**
是有效的,但根据错误消息,您可能必须按如下方式显式转换参数:
mystruct **var1;
x = myfunc ((void**) var1);
这是因为
myfunc
函数需要void**
类型。虽然可以将void*
隐式转换为任何其他指针,但双指针并非如此-您需要显式转换它。这个问题有点让人困惑。但是是的,void**
当然是合法有效的C语言,它的意思是“指向void
的指针”
我不确定您的调用示例,参数(“mystruct**var1”)没有意义。如果var1
的类型为mystruct**
,则调用应为a=func(var1)代码>,这可能是输入错误
强制转换应该可以工作,但您需要强制转换到void**
,因为这是函数所期望的。就像它看起来一样脏:有时不使用void**,您无法解决问题。编译器无法自动从mystruct**
强制转换到void**
考虑以下代码:
void stupid(struct mystruct **a, struct myotherstruct **b)
{
void **x = (void **)a;
*x = *b;
}
编译器不会抱怨在*x=*b
行中从myotherstruct*
到void*
的隐式转换,即使该行试图将指向myotherstruct
的指针放在只应放置指向mystruct
的指针的位置
事实上,错误在前一行,它将“指向可以放置mystruct
指针的位置的指针”转换为“指向可以放置任何指针的位置的指针”。这就是没有隐式强制转换的原因。当然,当您使用显式强制转换时,编译器假定您知道自己在做什么。是的,void**
完全可以接受,并且在某些情况下非常有用。还考虑到给定的声明>代码> Vo.*Foo和空>栏<代码>,编译器将知道Foo指向的对象的大小(指向指针,所有指针都是相同大小的,除非您不需要担心的几个古老平台),但是它不知道由BAR指向的对象的大小。(它可以指向任何大小的对象)。因此,您可以安全地对void**
指针执行指针算法,但对void*
指针执行而不是。您必须先将它们转换为其他对象,例如char*
。GCC允许您假装void*
和char*
是等效的,每个对象都指向一个b这是一个不标准的、不可移植的问题。中详细讨论了这个问题。简言之,他们说,将任意指针投射到指向空**
的指针是不可移植的;他们接着解释了这一点“这样的代码可能有效,有时也会被推荐,但它依赖于所有具有相同内部表示形式的指针类型(这是常见的,但不是通用的)。”他们接着解释说,“您使用的任何void**
值都必须是某个位置的实际void*
值的地址;类似(void**)的强制转换&dp
,尽管它们可能会关闭编译器,但它们是不可移植的(甚至可能不会执行您想要的操作)。”
因此,您可以通过以下代码安全/可移植地实现所需的行为:
some_type *var1 = foo();
void *tmp_void_ptr = (void *)var1;
myfunc(&tmp_void_ptr);
这将调用未定义的行为(通过指向错误类型的指针修改对象)。API刚刚被破坏;任何分配通用内存的分配类型函数(void*
)需要返回指针,而不是使用双指针参数。幸运的是,这些损坏的API可以被包装以修复它们…通过不同的指针修改它可能是未定义的,但这里没有这样做。我正在强制转换以消除错误,并且所有指针都可以以定义的方式强制转换到无效指针。为了避免UB,在尝试取消引用之前,您必须将其转换回正确的类型-这是给定的,因为您无论如何都无法取消引用void*
类型-编译器不知道底层类型。OP明确指出,使用void指针是为了可以发送不同的指针类型,因此在这里和其他地方都可以接受只有UB没有被正确地回滚,才会有UB。然后被调用的函数修改(或至少访问)通过错误的类型创建对象。当实际类型为mystruct*
且这些类型不兼容时,它将其读写为void*
,而这些类型不兼容。void**
与void*
不同;它不是通用的双指针。感谢修复;我已删除了我的评论并取消了否决票。