6

[Question inspired by a comment thread at this answer.]

As everyone knows, since C99 it's an error to call a function that hasn't been declared, preferably with a proper prototype.

But, going beyond that, I want my compiler to warn me if I define a function without a prototype declaration in scope, presumably included out of the same header file that the callers are using. (Unless the function is static, in which case all of this is moot.)

The reason should be obvious: If there's a prototype declaration in a header, and it's included by all the callers, but it's not included in the file where the function is defined, and if the function's actual definition somehow differs from the external prototype, then all the prototype checking done on behalf the callers is worthless, and in fact counterproductively wrong. There's a glaring error, but it's not guaranteed to be caught at all.

Are there common compilers which can check this? I tried both gcc and clang with -Wall, and they don't. (I would imagine Gimpel lint -- if it's still around -- would do this, but I don't have a copy.)

Ideally, I'd like it to also insist that the prototype exist in a separate header file, but that's different kettle of fish, so I don't insist on it. (The reason for this additional stipulation would be that some programmers, harried by the hypothetical warning message, might try to silence it by typing in an external prototype at the top of the .c file containing the definition, which, again, would defeat the purpose.)

Steve Summit
  • 45,437
  • 7
  • 70
  • 103
  • For that you probably should look at a *static code analyzer* instead of the compiler, because not declaring a prototype in a header file is not really a problem, as long as there is a declaration *somewhere* before the function is called. The declaration could even be part of the function definition itself. There are even people with code-styles that don't put prototypes in header files at all, but only in source files where the functions are called. – Some programmer dude May 17 '18 at 22:04
  • What do you mean by "global function". I assume "function with external linkage" – M.M May 17 '18 at 22:35
  • @Someprogrammerdude The thing about the separate header file was secondary; the primary concern is just having the "definition with no prototype" warning at all. I've clarified the question. But you're right, what I'm asking for sounds more like a separate analyzer -- except that GNU, at least, have declared their opposition to separate analyzers, have stated that the compiler ought to do everything that a separate lint-like program might once have done. (At least, they stated this once upon a time; I don't know if it's still their position.) – Steve Summit May 17 '18 at 23:00
  • @M.M Yes. Question clarified. – Steve Summit May 17 '18 at 23:01
  • There are quite a number of related options that help: `-Wmissing-prototypes`, `-Wstrict-prototypes`, `-Wold-style-definitions`, `-Wold-style-declarations`, One of the 'old-style' warnings isn't supported by `clang` (`-Wold-style-declaration`), and different versions of GCC may support more or less of them (older compilers support fewer of them). – Jonathan Leffler May 18 '18 at 04:44
  • Maybe [Recommended GCC warning options for C](https://stackoverflow.com/questions/154630/recommended-gcc-warning-options-for-c/154851#154851) has useful information. – Jonathan Leffler May 18 '18 at 04:53

2 Answers2

8

If you need an option which works on both gcc and clang, your best bet is probably -Wmissing-prototypes. As indicated in the gcc documentation, this will trigger if a global function is defined and either:

  • There was no previous declaration; or

  • The previous declaration had no prototype.

It does not complain if the previous declaration is contained in the same file as the definition; that is, it does not require that the declaration be in a header file.

This option must be enabled explicitly; it is neither enabled by -Wall nor by -Wextra.

Unfortunately, gcc only allows that option for C and Objective C; not for C++ (presumably because C++ does not allow non-prototyped function declarations). For gcc, another possibility would be -Wmissing-declarations. This warning is only produced if there was no previous declaration; a previous declaration with no prototype (i.e. int foo();) is not reported. But it works on both C and C++. Again, the warning option must be enabled explicitly.

Clang also has a -Wmissing-declarations option, but it means something completely different and it is enabled automatically (even if there are no -W options). For example, this option controls the complaints about empty declarations (int;), empty typedefs (typedef int;) and untagged composites which don't declare any object (struct { int a; };). Gcc also issues warnings about these constructs, but there is no obvious option to enable or disable these warnings.

rici
  • 234,347
  • 28
  • 237
  • 341
  • Yes! Thank you. (Yet another reminder that -Wall does *not* mean "all warnings". Grr.) – Steve Summit May 17 '18 at 23:13
  • It appears to be gcc only (clang accepts it, but doesn't seem to implement it), and it's got an 's' at the end (I edited your answer). – Steve Summit May 17 '18 at 23:14
  • @steve odd that it doesn't work with clang. Thanks for fixing the typo; i was just doing that when your edit went through. – rici May 17 '18 at 23:16
  • @steve: does -Wmissing-prototypes work with clang? I'm not in front of a computer just now. – rici May 17 '18 at 23:32
  • Yes, -Wmissing-prototypes does work with clang, and I see it's a better answer (it's what I *really* want) anyway. Thanks for the tips. – Steve Summit May 18 '18 at 03:07
  • @Steve: Updated the answer to discuss both missing-{declarations,prototypes}. What a mess.+ – rici May 18 '18 at 04:44
  • I note that `-Wmissing-declarations` allows `int function();` to declare a function. You need to go stronger — `-Wstrict-prototypes` (or `-Wmissing-prototypes`, but that isn't as good, IIRC). – Jonathan Leffler May 18 '18 at 04:45
  • @Jonathan: I think I just said that: "a previous declaration with no prototype (i.e. int foo();) is not reported." (Or did you happen to write your comment before my edit?). – rici May 18 '18 at 04:48
  • I just got to a machine so I could do some testing. The answer and previous comments were based on my memory and what I could convince an Android to find in the docs. – rici May 18 '18 at 04:49
  • @rici *gcc only allows that option for C and Objective C; not for C++* -- C++ doesn't really need it because the name mangling is bound to have the types of the arguments in it. So linker would fail if there is such a mismatch. – Ajay Brahmakshatriya May 18 '18 at 11:59
  • @ajay: that argument would equally apply to `-Wmissing-declarations`, which is available for C++. But the warning is useful; it is more informative than the linker error, and you'll see it earlier. Both gcc and clang provide the warning option for C++, but with different names. – rici May 18 '18 at 13:53
0

I added -Wstrict-prototypes and -Wold-style-definition in my project. These options are accepted by both GCC and Clang.

Relevant GCC documentation is https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html and Clang documentation is https://clang.llvm.org/docs/DiagnosticsReference.html.

In CMake, I used

add_compile_options($<$<COMPILE_LANGUAGE:C>:-Wstrict-prototypes> $<$<COMPILE_LANGUAGE:C>:-Wold-style-definition>)

to enable the options, because GCC will barf if these appear on g++ command line.

cc1plus: error: command-line option ‘-Wstrict-prototypes’ is valid for C/ObjC but not for C++ [-Werror]
cc1plus: error: command-line option ‘-Wold-style-definition’ is valid for C/ObjC but not for C++ [-Werror]

Consider also enabling -Wstrict-prototypes.

user7610
  • 25,267
  • 15
  • 124
  • 150