我制作了一个非常简单的程序来打印两个变量的地址。
#include<stdio.h>
int main()
{
int a,b;
printf("%u\n%u",&a,&b);
return 0;
}
但是,Clang-3.7编译器会发出警告:
警告:格式指定类型&#39; unsigned int&#39;但是参数的类型为&#39; int *&#39; [-Wformat]`
但是,当我使用GCC-5.x编译时,它没有发出任何警告。哪一项是正确的?
我知道的一件事是,执行unsigned int num=&a;
会出错,因为地址只能存储在指针中。但是,编译器在打印地址时发出警告是否正确?
答案 0 :(得分:9)
DROP TABLE IF EXISTS my_table;
CREATE TABLE my_table
(id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,string VARCHAR(12) NOT NULL);
INSERT INTO my_table (string) VALUES ('2b'),('1'),('2a'),('1b'),('1a'),('11');
SELECT * FROM my_table;
+----+--------+
| id | string |
+----+--------+
| 1 | 2b |
| 2 | 1 |
| 3 | 2a |
| 4 | 1b |
| 5 | 1a |
| 6 | 11 |
+----+--------+
SELECT * FROM my_table ORDER BY string + 0,string;
+----+--------+
| id | string |
+----+--------+
| 2 | 1 |
| 5 | 1a |
| 4 | 1b |
| 3 | 2a |
| 1 | 2b |
| 6 | 11 |
+----+--------+
是打印地址的正确格式说明符:
%p
C标准要求与printf("%p\n%p",(void*)&a, (void*)&b);
对应的参数应为%p
类型。所以演员都在那里。
C11,Reference:
p参数应该是指向void的指针。指针的值 转换为一系列打印字符,在 实现定义的方式。
使用不正确的格式说明符是undefined behavior。编译器不是必需来为未定义的行为生成任何诊断。所以gcc和clang都是正确的。
GCC 5.1确实在我的系统上发出警告而没有任何额外的警告
选项。和GCC godbolt produces warnings有更严格的编译器选项:void*
。通常,您应该使用最严格的编译器选项进行编译。
答案 1 :(得分:4)
打印地址(指针)的正确格式说明符为-Wall -Wextra
,您需要将参数转换为%p
。
因此,警告是有效的,应该在那里。
但是,当我使用GCC-5.x编译时,它没有发出警告
如果是void *
,请添加gcc
注意编译器选项并尝试编译。我相信它会抛出我们期待的(相同)警告。
注意:实际上是-Wall
,它会检查-Wformat
和printf()
家庭电话的提供参数的类型。 scanf()
启用-Wall
。
答案 2 :(得分:0)
您收到此错误是因为格式说明符%u
接受unsigned-integer
,而您在代码中提供的是指向内存位置的指针。
您可以通过将参数类型指定为(void*)
来打印指针所占的内存位置地址,这将不会产生任何错误,并以十进制格式打印内存位置的地址。
printf("%u\n%u",(void*)&a,(void*)&b);
另外,这不是打印指针的正确方法,正确的方法是使用说明符%p
,它将以十六进制格式打印内存位置的地址。
printf("%p\n%p",(void*)&a,(void*)&b);
希望有所帮助。