【问题标题】:warning: format ‘%p’ expects argument of type ‘void *’, but argument 3 has type ‘char **’警告:格式“%p”需要“void *”类型的参数,但参数 3 的类型为“char **”
【发布时间】:2018-09-07 06:18:07
【问题描述】:

此时我正试图在我的代码中打印出argv 的值,但是当我尝试编译它时,我得到了 warning: format ‘%p’ expects argument of type ‘void *’, but argument 3 has type ‘char **。我不确定这个警告是什么意思。 %p 即使是指针也不能用于argv 吗?

int main(int argc, char* argv[])
{
    printf("%s%p", "argv = ", argv);
}

【问题讨论】:

  • 那么投吧——printf("argv = %p\n", (void *)argv);?
  • 看起来 printf 需要一个“void *”类型的参数,但你给它的类型是“char **”。您希望编译器消息更明确多少?
  • @Jonathan 只是在没有解释或不知道机器内部发生了什么的情况下进行类型转换,很快就会导致未定义的行为。最好知道为什么编译器在这种情况下需要显式类型转换。
  • 将其转换为 (void*) 将修复警告,但输出可能不是您真正想要的。 %p 打印内存地址的文本表示,而不是地址处的数据。此外,它并不是专门用于 argv,而是用于任何指针。
  • @RolandIllig:你想解释一下吗?转换为void * 并返回必须是幂等的,所以我不确定您在转换为void * 时会看到什么风险,特别是因为标准明确要求为%p 传递的值必须是void *(否其他指针类型可接受)。

标签: c pointers


【解决方案1】:

那你为什么不投呢?

printf("argv = %p\n", (void *)argv);`

指定了%p指针(POSIX printf();C11 §7.21.6.1 The fprintf function):

p — 参数应为指向void 的指针。指针的值以实现定义的方式转换为打印字符序列。

由于char ** 不是void *,您需要进行显式转换。标准不允许编译器为您转换为 void *printf() 声明中的省略号表示发生默认参数提升,但这仅影响 float 类型和更小的整数类型比intshortchar 等)。

如今,在大多数机器上,这是无操作的。在我学习用 C 编程的(长期过时的)机器上,还没有 void *(对于标准来说太旧了),但等效的是 char *,而 char * 地址的值是给定的内存位置不同于任何其他类型的指针值——强制转换不是可选的。

请注意,我假设您打算打印地址的值。如果您打算打印内容,那么还有更多工作要做。

【讨论】:

  • 是的,我打算打印 argv 的内容,但它不应该包含地址作为其内容吗?
  • 有几种查看方式。最简单的是作为单个指针,打印该值是合法的(但是当通过printf() 打印值时,您需要将其转换为void *)。另一种看待它的方式是将其视为指向指针数组的第零个元素的指针,其中数组中的每个指针都指向一个字符串。这会将“内容”视为或查看为字符串数组,并且您将打印这些值,如mayur 在其answer 中所示。这两种观点都是有效的,但它们是不同的。
  • 对比void * 变量的使用也可能会有所帮助;这不需要强制转换,因为在转换点,两种类型都是已知的。 (当然,我在想void *addr = argv; printf("%p", addr);)。
【解决方案2】:

嗯,不是任何指针(类型)。

根据C11,章节§7.21.6.1,对于%p 转换说明符,

p

参数应为指向void 的指针。指针的值为 在实现定义中转换为打印字符序列 方式。

因此,参数必须是 void * 类型(或者,char*,因为它们具有相同的对齐要求)。任何其他类型的指针,都必须通过显式转换进行转换,因为指针没有默认参数提升。

类似

printf("%s%p", "argv = ", (void *)argv);

应该这样做。

【讨论】:

  • 这没有回答为什么在这种情况下需要显式类型转换。在许多其他上下文中,任何对象指针都会隐式转换为 void 指针。为什么不在这里?
  • @RolandIllig 正如我所提到的,没有默认参数提升 - 您指的是其他哪些情况?
  • void *ptr = argv; -- 不需要显式转换
【解决方案3】:

为了打印argv 和它的地址,你需要这样做

int main(int argc, char* argv[])
{
    int i;
    printf("address of argv = %p\n", (void *)argv);
    for (i = 0; i < argc; ++i)
    {
        printf("%s\n", argv[i]);
    }
    return 0;
}

【讨论】:

  • 您正在执行与问题不同的操作。您正在打印 argv 数组指向的字符串,但问题中的代码似乎正在尝试打印存储在 argv 中的地址。
猜你喜欢
  • 2014-04-23
  • 1970-01-01
  • 2018-11-03
  • 2013-05-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多