Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/68.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
void**在ANSI-C中是可接受的类型吗?_C_Void - Fatal编程技术网

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类型的函数,可以使用各种结构变量类型调用,以进行内存分配

  • C标准/任何C编译器中是否允许使用void**之类的类型
  • 我该如何解决这个问题?[我尝试将函数调用参数强制转换为
    mystruct**
    ,但没有成功]
  • -AD

    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*
    不同;它不是通用的双指针。感谢修复;我已删除了我的评论并取消了否决票。