【问题标题】:Void** as parameter requires castvoid** 作为参数需要强制转换
【发布时间】:2016-08-05 15:19:03
【问题描述】:

我在 C 中有一个函数,它需要接收指向数组的指针(具有未指定的类型)。

为此,我使用 void**,因为我会使用 void* 来接收未指定元素的数组。

不幸的是,有一个问题:编译器发出警告(从不兼容的指针类型传递 'f' 的参数 1)。如果我忽略警告并尝试执行程序,一切都会按预期工作。

摆脱警告的唯一方法是将我尝试传递给函数的任何内容都转换为 void**。

为什么 C 会这样?有没有更好的方法来解决警告?

PS:我需要使用带有标志 -std=gnu89 -pedantic -Wall 的 GCC 进行编译

示例

int f(void** param){ return 1; }

int main(){
    int *arr = malloc(sizeof(int) * 20);
    int i;
    for(i=0; i < 20; i++) arr[i] = i;
    f(&arr);
}

【问题讨论】:

  • int f(void** param){ return 1; } --> int f(void* param){ return 1; },不要使用**,可以使用单个指针读取指向数组的指针(void *
  • @AlterMann 我想更改arr 的分配如何?
  • @SouravGhosh 这正是我需要完成的。
  • 我想你可以从this question 及其答案中学到一些东西。不要只是略读它。值得花时间。
  • @SouravGhosh,那么,您需要取消引用函数内部传递的内容,*(int **)param = newaddress;

标签: c void-pointers


【解决方案1】:

指向任何类型的指针是void*,编译器不会抱怨转换为该类型。但是void** 不是指向任何东西的指针,它是指向指向任何东西的指针数组的指针,这与指向整数指针数组的指针完全不同,因此编译器会抱怨。 因此,要解决警告,是的,您需要显式转换。

【讨论】:

  • 感谢您的详细说明,但这如何回答这个问题?
  • 其中一个问题是,为什么 C 会有这样的行为?
  • “它是一个指向任何东西的指针数组的指针”。不,那是void*(*)[]void** 是指向任何东西的指针。
【解决方案2】:

虽然void * 是C 中的“通用指针”,但void ** 不是“指向指针的通用指针”。相反,它只不过是“指向void *特定指针,通用指针”。

在您的情况下,int ** 被隐式转换为 void **,这不是通用的。由于不能保证 void ** 能够保存所有指针变量(因此与 int ** 不兼容),因此编译器会发出警告。

这是由clang生成的警告:

main.c:7:7: warning: incompatible pointer types passing 'int **' to parameter of
      type 'void **' [-Wincompatible-pointer-types]
    f(&arr);
      ^~~~
main.c:1:14: note: passing argument to parameter 'param' here
int f(void** param){ return 1; }

要消除此警告,您可以在函数内使用int f(void* param);,并将param 转换为int **。不会有警告,因为void * 可用于存储任何指针(引自 N1570):

6.3.2.3 指针

1 指向 void 的指针可以转换为指向任何 对象类型。指向任何对象类型的指针都可以转换为 指向 void 并再次返回的指针;结果应比较等于 原始指针。

【讨论】:

  • 没有从int**void**的隐式转换,OP的代码是违反约束的
  • 该代码违反了约束,因为int**void ** 之间不存在隐式转换
  • @M.M 但似乎这是标准允许的,请参阅:port70.net/~nsz/c/c11/n1570.html#6.3.2.3p7
  • 6.2.7p2 似乎不相关。 6.3.2.3p7 说转换是可能的,但是其他部分说必须是显式转换(cast)
  • 查找与参数匹配的参数(遵循赋值运算符)
【解决方案3】:

看来你想修改函数内部数据的地址(不是值),你不能直接用void *来做,因为你不能用void *做算术,但是你可以传递第一个元素的大小和一大块字节(char *),假设你想在函数内部将arr的地址更改为arr + 1(数组的第二个元素):

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void f(void *ptr, size_t size)
{
    // char *p = *ptr;  Wrong, you can't dereference a void * without a cast
    char *p = *(char **)ptr; /* pointer to address of ptr */

    memmove(p, p + size, size); /* assign the address of ptr + 1 to ptr */
}

int main(void)
{
    int *arr = malloc(sizeof(int) * 20);
    int i;
    for (i = 0; i < 20; i++) arr[i] = i;
    f(&arr, sizeof arr[0]);
    printf("%d\n", arr[0]);
    return 0;
}

输出:

1

【讨论】:

    猜你喜欢
    • 2013-12-24
    • 1970-01-01
    • 1970-01-01
    • 2016-10-10
    • 2012-04-12
    • 1970-01-01
    • 2013-06-03
    • 2012-03-17
    • 1970-01-01
    相关资源
    最近更新 更多