views:

143

answers:

6

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?

+1  A: 

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

luiscubal
+8  A: 

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

Steve Jessop
+2  A: 

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.

Derrick Turk
+1  A: 

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.

Roman Cheplyaka
+2  A: 

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.

David Thornley
"The Standard requires diagnostics under some circumstances" -- no it doesn't, see quotation in my answer (it's from ISO/IEC 9899:TC2). Or can you point me to a place (possibly in some other ISO or ANSI C standard?) where it does?
Roman Cheplyaka
I have the draft C99 standard here (don't own a real copy), and in 5.1.1.3 I find "A conforming implementation shall produce at least one diagnostic message (identified in an implementation-defined manner) if a preprocessing translation unit or translation unitcontains a violation of any syntax rule or constraint, even if the behavior is also explicitly specified as undefined or implementation-defined." Is this omitted from the final version?
David Thornley
@Roman: Also, it looks to me that that's from the start of Annex I (informative), titled "Common Warnings". It refers to warning messages and not diagnostic messages (in standards, the exact wording can be important) and apparently isn't normative anyway.
David Thornley
@David: okay, now I see what you're referring to, thanks for explanation.
Roman Cheplyaka
You're not allowed to write your own version of `printf`, period, unless you make it `static`. Redefining external symbols, not to mention ones defined by the standard, results in undefined behavior. Whether you included `stdio.h` or not is a much more minor issue.
R..
+1  A: 

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 (e.g. 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 (e.g. 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.

supercat