[...]
For instance, suppose that a declaration for foo hasn't been
seen previously, and we have this:
int x = foo("abc");
in this situation, an implicit declaration is supplied: an unwritten, invisible
declaration that exists in the "mind" of the compiler, so to speak. [...]
(Kaz knows this, but the O.P. may not): The implicit declaration
of functions mentioned in FAQ 1.34 (and described more fully in 1.25)
occurs in "prehistoric C" and in the version of C first standardized
in 1989 ("ANSI C"). However, the C standard has continued to develop
over the last quarter-century, and implicit declaration is no longer
part of the language. As of the 1999 version of the standard, all
identifiers must be declared prior to use, period.
Summary:
- Compilers for modern C will produce error messages if you
try to use a function without declaring it,
- Compilers for old versions of C (or a modern compiler
that you've told to behave like an older one) will do as
Kaz and the FAQ describe, and
Compilers for 1990 C will also produce error messages.
$ cat test.c
int main(void)
{
foo();
}
GCC compiling as 1990 C:
$ gcc -Wall -std=c90 test.c
test.c: In function ‘main’:
test.c:3:3: warning: implicit declaration of function ‘foo’ [-Wimplicit-function-declaration]
test.c:4:1: warning: control reaches end of non-void function [-Wreturn-type]
GCC compiling as 1999 C:
$ gcc -Wall -std=c99 test.c
test.c: In function ‘main’:
test.c:3:3: warning: implicit declaration of function ‘foo’ [-Wimplicit-function-declaration]
The only difference we see here is that falling off the end of main without returning
a value is now "blessed" in 1999 C, and implicitly converted to a "return 0", so
there is no "control reaches end" warning.
When GCC is wearing its C90 hat, it's producing an extra diagnostic about implicit
functions. When GCC is wearing its C99 hat, it is producing a required diagnostic; but
only as a warning; it still provides the traditional behavior.
- Even with an older compiler it's questionable practice to
rely on implicit declarations. Declare what you use; it's
safer in the long run.
If you're using gcc, use at least these:
-Wall -Werror=implicit-function-declaration -Werror=missing-prototypes -Werror=strict-prototypes
-Werror=implicit-function-declaration causes the uses of undeclared functions to
be an error which fails compilation.
-Werror=strict-prototypes makes it a compilation-stopping error to have a function
declaration or definition that doesn't provide a prototype unless the prototype
is already established previously.
-Werror=missing-prototypes makes it a compilation-stopping error to define a function with external linkage without a prior prototype.
Why is the last one useful? For one thing, it stops you from accidentally
making internal functions external, so you make all the module private
functions static, reducing pollution of the external namespace.
More importantly, it catches the following situation:
module A:
#include "module_b.h"
...
module_b_function(42); /* prototype in scope, everything looks cool! */
module B:
/* Ooops, module B neglects to include its own module_b.h ! */
void module_b_function(char *str) { ... } /* does not match prototype */