简体   繁体   English

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

[英]Are printf/sprintf compiler warnings a conceptual break?

I have noticed that a large number of C compilers issue warnings when the conversion specifiers in the format string of the printf/sprintf functions do not match the type or the count of the corresponding arguments. 我注意到,当printf / sprintf函数的格式字符串中的转换说明符与相应参数的类型或计数不匹配时,大量C编译器会发出警告。

That seems to me like a conceptual break since C doesn't have built-in functions according to the language specification. 在我看来,这似乎是一个概念上的突破,因为根据语言规范,C没有内置函数。

All the compiler should know about printf/sprintf is their prototypes and not their semantics. 所有编译器都应该知道printf / sprintf是他们的原型而不是他们的语义。 I know that printf/sprintf are standard C functions, but yet they reside in a separate library, libc, and you have to include stdio.h to import their prototypes. 我知道printf / sprintf是标准的C函数,但是它们存在于一个单独的库libc中,你必须包含stdio.h才能导入它们的原型。

What many compilers do instead is analyze the format string which could as well be supplied at runtime. 许多编译器所做的是分析格式字符串,该格式字符串也可以在运行时提供。

Does the above make sense? 以上是否有意义?

"All the compiler should know about printf/sprintf is their prototypes and not their semantics". “所有编译器都应该知道printf / sprintf是他们的原型,而不是他们的语义”。

That's the part that isn't true. 这是不正确的部分。 As far as the standard is concerned, any part of a C implementation is "allowed" to know about any other part, and to issue diagnostics that may be helpful to the user. 就标准而言,C实现的任何部分都“被允许”了解任何其他部分,并发布可能对用户有帮助的诊断。 Compiler intrinsics aren't required by the standard, and neither is this particular diagnostic, but they certainly aren't forbidden. 标准不要求编译器内在函数,这也不是特定的诊断,但它们当然不是禁止的。

Note that (as far as the standard is concerned) the standard library is special, it's not just any old linked library. 请注意(就标准而言)标准库是特殊的,它不仅仅是任何旧的链接库。 If a particular implementation/compiler even provides a mechanism for the user to link against a different version of the standard library, the standard certainly doesn't require it to "work" when that alternative library has different semantics from what is laid out in the standard. 如果特定的实现/编译器甚至为用户提供了一种链接不同版本的标准库的机制,那么当该替代库具有与其中所列出的语义不同的语义时,该标准当然不要求它“工作”。标准。

So in that sense, everything in the standard library is "bult-ins". 所以在这个意义上,标准库中的所有内容都是“bult-ins”。 It's part of the C language specification. 它是C语言规范的一部分。 Compilers are allowed to act on the assumption that it behaves as the standard requires. 允许编译器在假设其行为符合标准要求的情况下执行操作。

Of course, if the format specifier isn't known until runtime, then the compiler can't do a static check of the varargs. 当然,如果格式说明符在运行时才知道,那么编译器就无法对varargs进行静态检查。 But when it is known at compile time, the compiler can assume the behaviour of printf just as validly as it can assume the behaviour of memcpy , or of integer addition. 但是当它在编译时已知时,编译器可以假设printf的行为与它可以假设memcpy或整数加法的行为一样有效。

If I read your question correctly, I agree with your premise that verification of printf and friends' format strings by the compiler is an activity conceptually unlike the other sorts of static checking (syntax, type, etc.) done by the compiler. 如果我正确地阅读了你的问题,我同意你的前提,即编译器对printf和朋友的格式字符串的验证是一种概念性的活动,与编译器完成的其他种类的静态检查(语法,类型等)不同。

However, it is permitted by the standard, and helps us poor programmers out greatly. 但是,它是标准所允许的,并且可以帮助我们糟糕的程序员。

Compiler's task here is just to give you some useful hints. 编译器的任务只是给你一些有用的提示。 This behaviour is not covered by standard. 标准不涵盖此行为。

An implementation may generate warnings in many situations, none of which are specified as part of this International Standard. 实施可能会在许多情况下产生警告,其中没有一个被指定为本国际标准的一部分。

In theory, nothing prevents compiler from warning you about (potentially) incorrect usage of, say, QT library. 从理论上讲,没有什么能阻止编译器警告你(可能)错误地使用QT库。

And printf is standard function in the sense that it (including its semantics) is covered by ISO C standard. printf是标准功能,因为它(包括其语义)被ISO C标准所涵盖。

The Standard requires diagnostics under some circumstances, but does not disallow general diagnostics. 标准在某些情况下需要诊断,但不禁止常规诊断。 Any implementation is free to issue a diagnostic for any reason, including improper use of printf() or the overuse of the letter Q. Obviously, some of these reasons are more useful than others. 任何实现都可以出于任何原因自由发布诊断,包括不正确使用printf()或过度使用字母Q.显然,其中一些原因比其他原因更有用。

Moreover, if you include a library, all the visible identifiers in it become reserved. 此外,如果包含库,则其中的所有可见标识符都将保留。 You are not allowed to #include <stdio.h> and have your own definition of printf (see 7.1.3 of the draft C99 standard). 您不能#include <stdio.h>并拥有自己的printf定义(参见C99标准草案的7.1.3)。 This means that the implementation is free to assume that you're using the standard printf and treat it as if it were a required part of the standard. 这意味着实现可以自由地假设您正在使用标准printf并将其视为标准的必需部分。

These kind of warnings indicate likely bugs and, as a result, are useful. 这些警告表明可能存在错误,因此非常有用。

Yes, it might look inconsistent to have special cases for warnings in the compiler(assuming <stdio.h> doesn't just have a __printf_format_warning attribute or something like that), but then again, if it useful and helps solve some bugs(maybe even security bugs), then why not have them? 是的,在编译器中有警告的特殊情况可能看起来不一致(假设<stdio.h>不仅具有__printf_format_warning属性或类似的东西),但是如果它有用并且有助于解决一些错误(也许甚至安全漏洞),为什么不拥有它们呢?

I mean, it's not like everyone just replaces their libc with their own, with different printf semantics... 我的意思是,并不是每个人都只用自己的libc替换他们的libc,具有不同的printf语义......

The ultimate purpose of programming language standards is to help programmers write programs that behave as intended. 编程语言标准的最终目的是帮助程序员编写符合预期的程序。 There is nothing in the standard that says a compiler should issue a warning if it encounters "bigvar = byte3 << 24 + byte2 << 16 + byte1 << 8 + byte0;", but since the results probably aren't what the programmer intended, many compilers will issue a warning. 标准中没有任何内容表明如果遇到“bigvar = byte3 << 24 + byte2 << 16 + byte1 << 8 + byte0;”,编译器应该发出警告,但由于结果可能不是程序员打算,许多编译器会发出警告。 The only limitation the standards impose upon warnings is that they must not prevent the successful compilation of a legitimate program (eg a compiler which failed with an error after outputting 999 warnings, or which output so many warnings that compilation would, for all practical purposes, never complete, would be non-conforming). 标准对警告施加的唯一限制是它们不能阻止合法程序的成功编译(例如,在输出999警告后输出错误的编译器,或者为了所有实际目的,输出如此多的警告编译将会,永远不会完成,不符合规定)。

There isn't any requirement that the compiler "know" about the standard libraries, but nor is there any requirement that it not know about them if someone #includes the normal headers. 没有任何要求编译器“知道”标准库,但也没有要求如果有人#includes正常的标题,它就不知道它们。 Indeed, if a program includes <stdio.h> I think it would be permissible under the standard for a compiler to replace a printf call that it can understand with something that might be easier to process at run-time (eg it could replace printf("Q%5d",foo); with "putch('Q'); __put_int(foo,5);" if desired). 实际上, 如果一个程序包含<stdio.h>我认为在编译器的标准下允许替换一个可以在运行时更容易处理的东西(例如它可以替换printf)的printf调用是允许的(“Q%5d”,foo);“putch('Q'); __put_int(foo,5);”如果需要,“。 If a program does not #include <stdio.h> such translation would be forbidden. 如果程序没有#include <stdio.h>,则禁止此类翻译。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM