Visual Studio 2015 年警告 C4477

Warning C4477 in Visual Studio 2015

当我编译以下代码时,Visual studio 显示 C4477 的警告。为什么 visual studio 会生成此警告?我该如何修复此代码?

警告:警告 C4477:'printf':格式字符串“%d”需要一个类型为 'int' 的参数,但可变参数 1 的类型为 'int *'

#include <stdio.h>

int main(void) {
    int num = 0;
    int *pi = &num;

    printf("Address of num: %d Value: %d\n", &num, num);
    printf("Address of pi: %d Value: %d\n", &pi, pi);

    return 0x0;
}

因为您使用的格式说明符不正确。 %d是打印一个int。要打印指针,请使用 %p 并转换为 void*:

printf("Address of num: %p Value: %d\n", (void*)&num, num);
printf("Address of pi: %p Value: %p\n", (void*)&pi, (void*)pi);

需要转换为 void*,因为可变参数函数不会按照 %p 的要求进行从 type *void * 的任何类型转换。引用标准:

7.21.6 格式化 input/output 函数(C11 草案)

p The argument shall be a pointer to void. The value of the pointer is converted to a sequence of printing characters, in an implementation-defined manner.

换句话说,您的参数 &num(或 (void *) &num 形式)告诉编译器您希望将 num 的地址传递给函数,而不是 num 的值。带有 %d 格式说明符的 printf 函数应该是一个值,而不是地址。抱怨是编译器意识到了这种差异。

注意:在 32 位工作中,一个地址和一个 int 都是 32 位的,所以东西(即 %d)可以正常工作。但是,在 64 位世界中,int 仍然是 32 位长,但地址是 64 位。 IE。您不能用 %d 准确表示指针的值。这就是创建 %p 的原因。它(编译器)足够聪明,可以在为 32 位编译时将 %p 参数处理为 32 位量,在为 64 位编译时将 %p 参数处理为 64 位量。

阅读计算机体系结构、硬件堆栈及其位大小。当您使用它时,您可能还希望了解小端和大端之间的区别。