我在想如何让一个函数发出编译时警告?
这是因为当我们在printf(scanf)的第一个参数中使用错误的格式说明符与匹配该类型说明符的变量并使用gcc的-Wall选项进行编译时,编译器会发出警告。
现在,据我所知,printf和scanf通常作为变量参数函数来实现,我不知道有什么方法可以在编译时检查字符串的值,更不用说如果某些内容不匹配就发出警告了。
有人能解释一下如何得到编译器警告吗?
警告是与实现(即编译器和C标准库)相关的。你可能会得到很少的警告(看看tinycc...),甚至没有警告...
我正在关注最近的GCC(例如4.9或10...)在Linux上。
您会收到这样的警告,因为printf
使用适当的__attribute__
进行声明(请参阅GCC function attributes)
(使用GCC,您也可以使用format
属性声明自己的类似于printf
的函数...)
顺便说一句,符合标准的编译器可以非常特别地实现<stdio.h>
头文件。因此,它可以通过更改内部状态而不读取任何头文件文件来处理#include <stdio.h>
。
您甚至可以添加自己的函数属性,例如通过使用您的GCC插件自定义您的GCC。
printf()
不仅是标准的一部分,它还有着众所周知的格式字符串契约(甚至在很多自定义函数中使用),可以经受得住一些静态诊断,那么为什么不把这种调试辅助功能提供给程序员呢? - user2371524printf如何触发编译器警告?
一些编译器在编译时分析printf()
和scanf()
的格式和其他参数类型。
printf("%ld", 123); // type mis-match `long` vs. `int`
int x;
printf("%ld", &x); // type mis-match 'long *` vs. `int *`
如果格式已计算,则不会发生该检查,因为这是一个运行时问题。
const char *format = foo();
printf(format, 123); // mis-match? unknowable.
你说得没错,编译器警告特定函数确实很不寻常。
printf
(以及scanf
和相关函数)格式说明符的警告非常罕见,但是这些函数本身就非常罕见。
正如其他答案所解释的那样,编译器至少可以“知道”某些函数并执行特殊的、额外的编译时检查,因为printf
、scanf
和它们的伙伴同时非常罕见又非常流行,所以编译器进行这种额外检查是相当合适的,尽管它很不寻常。
从前(我在谈论 ANSI 之前的 K&R 时代),C 程序员知道他们必须小心地调用带有正确数量和类型参数的函数。(在那个时代,唯一自动检查的方法是使用lint
,一些程序员使用了它,但许多程序员没有。)如果你习惯于小心谨慎,对于printf
和它的伙伴也很容易小心谨慎。
sqrt(144)
是一个错误,会悄悄地给出神秘的结果,但今天没问题。)printf
困惑的程序员。如果您完全习惯于函数原型提供的保护措施,那么为什么会出现这种神秘的情况,还是一个相当大的谜。int i = 3;
float f = 4.5;
printf("i as a float is %f, f as an int is %d\n", i, f);
不起作用。与过去不同,我怀疑现在很难记住,当您调用printf
(但几乎只有在调用printf
时),它是您的工作来正确获取所有类型,因为编译器不会插入任何隐式转换。
底线是,今天,编译器不仅可以警告调用printf
等函数时的不匹配,我认为这几乎是一种道义上的必要。当我们引入函数原型时,我们承诺程序员函数参数的类型安全性,因此在涉及printf
时悄悄撤回该承诺真的不公平。
[附言:是的,我当然知道为什么函数原型不能保证像printf
这样的可变参数函数的完全类型安全。但这与我的论点无关。另外,是的,我知道,生活并不公平,所以你可以称呼我为一个高谈阔论的老软蛋。 :-) ]
printf
的数据类型,即使有可变数量的参数?所以它可以轻松地判断您是否存在不匹配的数据和说明符。 - lurker