printf / sprintf编译器警告是否有概念上的突破?

我注意到,当printf / sprintf函数的格式字符串中的转换说明符与相应参数的类型或计数不匹配时,大量C编译器会发出警告。

在我看来,这似乎是一个概念上的突破,因为根据语言规范,C没有内置函数。

所有编译器都应该知道printf / sprintf是他们的原型而不是他们的语义。 我知道printf / sprintf是标准的C函数,但是它们存在于一个单独的库libc中,你必须包含stdio.h才能导入它们的原型。

许多编译器所做的是分析格式字符串,该格式字符串也可以在运行时提供。

以上是否有意义?

“所有编译器都应该知道printf / sprintf是他们的原型,而不是他们的语义”。

这是不正确的部分。 就标准而言,C实现的任何部分都“被允许”了解任何其他部分,并发布可能对用户有帮助的诊断。 标准不要求编译器内在函数,这也不是特定的诊断,但它们当然不是禁止的。

请注意(就标准而言)标准库是特殊的,它不仅仅是任何旧的链接库。 如果特定的实现/编译器甚至为用户提供了一种链接不同版本的标准库的机制,那么当该替代库具有与其中所列出的语义不同的语义时,该标准当然不要求它“工作”。标准。

所以在这个意义上,标准库中的所有内容都是“bult-ins”。 它是C语言规范的一部分。 允许编译器在假设其行为符合标准要求的情况下采取行动。

当然,如果格式说明符在运行时才知道,那么编译器就无法对varargs进行静态检查。 但是当它在编译时已知时,编译器可以假设printf的行为与它可以假设memcpy或整数加法的行为一样有效。

如果我正确地阅读了您的问题,我同意您的前提,即编译器对printf和朋友的格式字符串的validation在概念上是一种活动,与编译器完成的其他种类的静态检查(语法,类型等)不同。

但是,它是标准允许的,并且可以帮助我们糟糕的程序员。

编译器的任务只是给你一些有用的提示。 标准不涵盖此行为。

实施可能在许多情况下产生警告,其中没有一个被指定为本国际标准的一部分。

从理论上讲,没有什么能阻止编译器警告你(可能)错误地使用QT库。

printf是标准function,因为它(包括其语义)被ISO C标准所涵盖。

该标准在某些情况下需要诊断,但不禁止一般诊断。 任何实现都可以出于任何原因自由发布诊断,包括不正确使用printf()或过度使用字母Q.显然,其中一些原因比其他原因更有用。

此外,如果包含库,则其中的所有可见标识符都将保留。 您不能#include 并拥有自己的printf定义(参见C99标准草案的7.1.3)。 这意味着实现可以自由地假设您正在使用标准printf并将其视为标准的必需部分。

这些警告表明可能存在错误,因此非常有用。

是的,在编译器中有警告的特殊情况可能看起来不一致(假设不仅具有__printf_format_warning属性或类似的东西),但是如果它有用并且有助于解决一些错误(也许甚至安全漏洞),为什么不拥有它们呢?

我的意思是,并不是每个人都只是用自己的libc替换他们的libc,具有不同的printf语义……

编程语言标准的最终目的是帮助程序员编写符合预期的程序。 标准中没有任何内容表示如果遇到“bigvar = byte3 << 24 + byte2 << 16 + byte1 << 8 + byte0;”,编译器应发出警告,但由于结果可能不是程序员打算,许多编译器会发出警告。 标准对警告施加的唯一限制是它们不能阻止合法程序的成功编译(例如,在输出999警告后输出错误的编译器,或出于所有实际目的,输出如此多的警告编译将会,永远不会完成,不符合规定)。

没有任何要求编译器“知道”标准库,但是如果某人#includes正常的标题库,也没有要求它不知道它们。 实际上, 如果一个程序包含,我认为在编译器的标准下允许替换一个可以在运行时更容易处理的东西来理解的printf调用是允许的(例如它可以替换printf) (“Q%5d”,foo);“putch(’Q’); __put_int(foo,5);”如果需要,“。 如果程序没有#include ,则禁止此类翻译。