什么是以及如何解决警告:格式 '%p' 需要类型为 'void *' 的参数,但打印时参数 2 的类型为 'int *' [-Wformat=]

3 c compiler-warnings

我有以下代码:

#include<stdio.h>

int main(void){
  int array[5]={10,20,30,40,50};
  int *p;
  p=array;
  printf("%p\n", array);
  printf("%p\n", p);
  printf("%p\n", &array[0]);
  printf("%p\n", &p[0]);
  printf("%p\n", &(*array));

  return 0;
}
Run Code Online (Sandbox Code Playgroud)

使用 GCC 编译此代码并打印出地址的值%p会给出以下警告:

01.c: In function ‘main’:
01.c:7:12: warning: format ‘%p’ expects argument of type ‘void *’, but argument 2 has type ‘int *’ [-Wformat=]    printf("%p\n", array);
           ~^     ~~~~~
           %ls
01.c:8:12: warning: format ‘%p’ expects argument of type ‘void *’, but argument 2 has type ‘int *’ [-Wformat=]    printf("%p\n", p);
           ~^     ~
           %ls
01.c:9:12: warning: format ‘%p’ expects argument of type ‘void *’, but argument 2 has type ‘int *’ [-Wformat=]    printf("%p\n", &array[0]);
           ~^     ~~~~~~~~~
           %ls
01.c:10:12: warning: format ‘%p’ expects argument of type ‘void *’, but argument 2 has type ‘int *’ [-Wformat=]    printf("%p\n", &p[0]);
           ~^     ~~~~~
           %ls
01.c:11:12: warning: format ‘%p’ expects argument of type ‘void *’, but argument 2 has type ‘int *’ [-Wformat=]    printf("%p\n",
&(*array));
           ~^     ~~~~~~~~~
           %ls ```
Run Code Online (Sandbox Code Playgroud)

我该如何解决它们以及它们为什么会发生?另外,什么是%ls

dbu*_*ush 5

任何类型的对象指针都可以在void *不进行强制转换的情况下隐式转换为 a ,反之亦然。

但是,%p格式说明符printf显式需要一个void *参数,并且因为printf是一个可变参数函数,所以不会发生隐式转换。

void *是需要显式强制转换为的罕见情况之一:

printf("%p\n", (void *)array);
printf("%p\n", (void *)p);
printf("%p\n", (void *)&array[0]);
printf("%p\n", (void *)&p[0]);
printf("%p\n", (void *)&(*array));
Run Code Online (Sandbox Code Playgroud)

在大多数实现中,您可能会接触到对象指针并void *具有相同的表示形式。然而,这在一般情况下不一定是正确的,并且未能强制转换可能会导致系统上的未定义行为,而这并非如此。

相比之下,调用foo下面的函数不需要强制转换:

void foo(void *p)
{
    printf("p=%p\n", p);
}

int main()
{
    int x;
    foo(&x);
}
Run Code Online (Sandbox Code Playgroud)

因为参数的类型在编译时是已知的。

  • @DuarteArribas正确,在使用“%p”时始终强制转换为“void *”(如果它还不是该类型)。 (3认同)