简体   繁体   中英

How to turn “implicit declaration” warnings in $CC into errors?

(I first started writing C programs in somewhere around 1993. Times were different back then, compilers may have been different, but I recall that when one attempts to refer to a C function that is not declared, one gets an error. Additionally, if the function is later defined, perhaps in another translation unit, and the "signatures" don't match, then you get another error.)

I am currently using GCC 4.4.3. I am perplexed as to why GCC is so forgiving on me (intentionally in the example) mismatching (optional) declaration of bar and its definition in bar.c which obviously will result in an fatal adressing error - since bar wants an address and is given an integer, it ends up de-referencing that integer as an address. A strict compiler, or so I think, would abort on me with an error. Am I missing something? My build command line is as follows:

cc -o foobar -g -Wall -std=c99 -fexec-charset=ISO-8859-1 -DDEBUG foo.c bar.c

With foo.c :

int main()
{
    int a;

    bar(a);

    return 0;
}

and bar.c :

void bar(int * a)
{
    *a = 1;
}

I have intentionally omitted declaration of bar and also intentionally pass it an integer (could be anything really) instead of an address as its actual definition would require. The bottomline for me is: because $(CC) does not stop me, I end up with a segmentation fault (x86, Ubuntu 10.04). I am aware that a compliant C (C99?) compiler would implicitly create an int bar(void) declaration for bar if none found, but in this case that's obviously not what I want at all! I want to protect myself from kinds of errors where I make the human mistake of mismatching declarations and definitions or omitting the former altogether.

I tried to instead compile-only -- with -c compiler switch -- but it doesn't matter as it still succeeds with warnings. The linker might barf though, but I want the compiler to stop me before that happens.

I do not actually want to turn my warnings into errors with say -Werror , because:

  • I could have included the wrong float bar(double a); at the top of foo.c , which eliminates the warning altogether, but doesn't change the fact that the resulting program crashes. Alas, a program that compiles successfully without warnings (even with the -Wall switch) and beautifully crashes at runtime.
  • I have and will have other types of warnings that should stay warnings and not prevent successful builds.
  • It would be dealing with the effect of the problem, rather than the problem itself
  • It's not just the types of warnings, but also particular instances. I wouldn't want to turn a specific warning code into error because in some instances, that would not be applicable. This would be too coarse of a solution which doesn't take into account the specifics of and the context in which the warning occurred.

To turn this warning into an error when compiling with gcc , pass the switch -Werror=implicit-function-declaration to the compiler.

Trying to answer your "why" question: yes, it might look odd that this is by default a warning and not an error. This is for historical reasons. For details, see eg Why does/did C allow implicit function and typeless variable declarations? , or read it in Ritchie's own words at http://cm.bell-labs.com/who/dmr/chist.html .

You could probably force additional warnings for gcc:

-Wmissing-prototypes
-Wmissing-declarations

Using both (along with -Werror) will probably help you to avoid such situations, but require some more code writing.

Inspired by this .

EDIT: Example

// file: mis1.c
int main(void)
{
    int a;

    bar(a);

    return 0;
}

// file: mis2.c
#include <stdio.h>

double bar(double a)
{
    printf("%g\n", a);
    return a;
}

Compiling with gcc 3.3.4 (DJGPP) as:

gcc -Wall -Wmissing-prototypes -Wmissing-declarations -Werror mis2.c mis1.c -o mis.exe

Compiler output:

mis2.c:5: warning: no previous prototype for `bar'
mis1.c: In function `main':
mis1.c:6: warning: implicit declaration of function `bar'

Fix? #Include the following file in both files:

// file: mis.h
extern int bar(int);

Recompiling you get:

mis2.c:6: error: conflicting types for `bar'
mis.h:3: error: previous declaration of `bar'

Fix? Define and declare bar everywhere in the same way, correct, for example, mis.h:

// file: mis.h
extern double bar(double);

Likewise you could change bar() in mis2.c to match that of mis.h.

From the gcc docs on warnings :

-Wimplicit-function-declaration (C and Objective-C only) Give a warning whenever a function is used before being declared. In C99 mode (-std=c99 or -std=gnu99), this warning is enabled by default and it is made into an error by -pedantic-errors. This warning is also enabled by -Wall.

...

-pedantic-errors (my emphasis) Like -pedantic, except that errors are produced rather than warnings.

...

-pedantic Issue all the warnings demanded by strict ISO C and ISO C++; reject all programs that use forbidden extensions, and some other programs that do not follow ISO C and ISO C++. For ISO C, follows the version of the ISO C standard specified by any -std option used.

It looks to me that -pedantic-errors will do what you want (turn these warnings into errors), however it sounds like it will also turn on a host of other checks you may or may not want. =/

The closest I found to a solution to my problem was to simply use the flag -combine which indirectly causes the compiler to abort compilation when attempting to call a function that is missing a prototype or where prototypes mismatch or do not match the definition.

I am afraid it has drawbacks though. Since input files now are combined in one compilation run, one ends up with a single object file, which has some implications of its own. In short, -combine does something more than just fix my problem, and that may be a problem in itself.

You can turn all warning to error with

cc [..] -Werror [..]

. This will partially solve your problem.

  • I could have included the wrong float bar(double a); at the top of foo.c, which eliminates the warning altogether, but doesn't change
    the fact that the resulting program crashes. Alas, a program that
    compiles successfully without warnings (even with the -Wall switch)
    and beautifully crashes at runtime.

Herefore it is essential, additional to other measures, to include the same header file (including the prototype) in foo.c and bar.c . This ensures that the correct prototype is applied at both places.

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