简体   繁体   中英

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.

That seems to me like a conceptual break since C doesn't have built-in functions according to the language specification.

All the compiler should know about printf/sprintf is their prototypes and not their semantics. 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.

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".

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. 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". It's part of the C language specification. 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. 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.

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.

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.

And printf is standard function in the sense that it (including its semantics) is covered by ISO C standard.

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.

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). 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.

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?

I mean, it's not like everyone just replaces their libc with their own, with different printf semantics...

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. 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).

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. 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). If a program does not #include <stdio.h> such translation would be forbidden.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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