为什么 &(void *) 和 void** 不兼容?

7

尽管我的代码可以正常运行,但是我收到了不兼容指针类型的错误警告。首先,这里是我代码的简化版本:

typedef struct {
    int field1;
    int field2;
} my_struct;

void some_function(void **data){
    // do something with *data
}

int main(int argc, char *argv[]){
    my_struct *ptr = malloc(sizeof(my_struct));
    ptr->field1 = 5;
    ptr->field2 = 17;
    some_function(&ptr);
}

my_struct类型是一个示例,但我实际上使用了多个类型,因此some_func必须接受void**而不是my_struct**。每次以上述方式调用some_func时,我都会收到以下警告,但我的代码可以正常工作。

warning: passing argument 1 of ‘my_func’ from incompatible pointer type

我不确定为什么这些类型不兼容,并希望以某种方式消除警告。如有答案,请自由解释为什么会发生这种情况,如果可能的话,如何消除警告(cpp指令,也许?)。谢谢!


请注意,&(void *)并不存在。&只是一个运算符,而不是类型的一部分。 - Oliver Charlesworth
@Oli:虽然在C语言中,这个意思非常明确 :) (当然,在C++中可能会有其他的意思) - Billy ONeal
我所说的 &(void *) 是指 &(some_pointer) 的结果。感谢您的快速回复 - 我刚开始学习 C 语言。 - Douglas Adam Smith II
2个回答

11

使用 void * 参数类型。

void ** 不是通用指针类型,void * 才是。


1
作为一个旁问:void ** 甚至有什么意义吗?也就是说,它有用处吗? - Kninnug
3
为什么它没有任何意义呢?它是一个指向指针的指针,指向void类型。当你需要一个指向指针的指针时,它就非常有用。 - user529758
啊,Billy ONeal的回答更深入地探讨了这个问题。我应该去睡觉了。 - Kninnug
2
@Kninnug:一个典型的场景是当你需要返回一个void*,但已经在使用函数的返回值做其他事情了——你最终会使用一个输出参数,它的类型是void**。(请参见我的答案中的示例) - Billy ONeal

5

void* 表示(实质上)“指向未指定类型内存区域的指针”。

void** 表示(实质上)“指向包含指向未指定类型内存区域的指针的内存区域的指针”。

注意中间的代码块有一个类型 -- 一个 void* 类型的数组。你传入的是一个有效的 mystruct* 数组,这是一种不同的类型。所以编译器会发出警告。

在 C++ 中,当尝试将 Derived** 转换为 Base** 时也会出现类似问题;但在 C 中也适用。(void* 就像所有指针类型的“基类”)考虑这样一段代码:

void does_things(void** outParameter)
{
    *outParameter = malloc(42); // Looks fine; writing void* to void* :)
}

int main()
{
    my_struct* x = /*...*/;
    does_things(&myStruct); // Ut oh, tries to make x point to
                            // something that is *not* a my_struct
}

"void*的意思(实际上)是“指向未命名内存区域的指针”。" - 不完全是这样;它的意思是“指向未被指定类型的内存区域的指针”。由void指针引用的对象仍然可以具有已声明或有效的类型。 - davmac
@davmac:这就是我所说的“有效”的意思 :) 我觉得在这里详细说明不会对答案有帮助。 - Billy ONeal
1
@davmac:C标准描述了一个抽象的机器,它与实际机器的行为非常不同。对于实际机器来说,内存只是一堆位。如果我们想要C标准技术描述正在发生的事情,我们必须提出存储持续时间以及某物体意味着什么等问题;但这些都无法回答问题,因此不适合用于描述高级概念性思想的答案。如果您不喜欢它,可以将答案投下反对票;但我不会因此做出任何更改。 - Billy ONeal
我想一个不那么抽象的例子是,如果你取一个 int 变量的地址并将其强制转换为 void *。指针所指向的内存区域是否是无类型的?不,它显然是 int 类型的。编译器可以意识到这一点,并且如果你认为它是其他类型("未定义行为"),则可能会做出意外的事情。我不会对你的答案进行投票;我的评论仍然有效,你的回复也是如此。就让它保持这样吧;读者可以自己做出决定,而且公开讨论是好的。任何对此感兴趣的人都应该搜索“类型转换”和“未定义行为”。 - davmac
1
@davmac:不,显然内存没有类型。内存本身没有类型。如果你想用C抽象机器的术语来谈论事物,那么“内存”这个概念并不存在——只有具有特定存储期限的对象。但正如我之前所说,所有这些都与问题无关。 - Billy ONeal
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接