Preamble: My C may be fairly rusty; I first started writing C programs in somewhere around 1993 -- compilers may have been different back then, but I recall that when one attempted to refer to a C function that was not declared, the compiler would abort. This is from memory.
Currently, I am perplexed as to why GCC (4.4.3) is so forgiving on me when I [intentionally] mismatch or omit declaration of bar below, with its definition in bar.c. Because the compiler does not warn me, the program proceeds to a fatal addressing error at runtime -- 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 would 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, as mentioned, intentionally pass it an integer (could be anything really) instead of an address that its actual definition would otherwise mandate. 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 otherwise found, but in this case that's obviously not what I want at all!
I want to protect myself from the kind of errors -- where I make the human mistake of mismatching declarations and definitions or omitting the former altogether.
I tried to instead just invoke the compiler without the linking step (with the -c switch) -- but it doesn't matter as compiling still succeeds with warnings. The linker might complain though, but I want the compiler to stop me before that happens.
I do not actually want to turn all my warnings into errors (e.g. with -Werror), because:
I could have included the wrong float bar(double a); at the top of foo.c, which would eliminate 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) but still is faulty
I have and will have other types of warnings that should stay warnings and not prevent successfully building the program
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 thereof; I wouldn't want to turn a specific warning into an 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 e.g. 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.
Related
So i just wasted an hour trying to figure out why my program crashed. As it happens, i forgot to put in the return statement of my function.
the function was about as follows:
structType name(2 parameters){
.....
}
I am used to getting warnings, that the return statement is missing.
Why didn't it do so here and how can i turn that feature on?
[I code in C]
EDIT: using GCC
The reason why there is no warning from omitted return statement is that it isn't "wrong" - the C standard explicitly allows it, and such a program is well-defined; only, you're not to use the return value if none was actually returned.
Whatever the warnings that are emitted by default are mostly those that the C standard names as constraint violations - a conforming compiler must diagnose these. Hence, using -pedantic-errors or -std=c17 or similar is not going to do anything at all, because it makes the compiler being more pedantic (i.e. more diagnostics-conforming) about following the C standard which says that this is OK after all.
In GCC the warning can be controlled with -Wreturn-type, which will enabled by -Wall too. (Why aren't you using -Wall?!):
% echo 'int foo() { }' > noreturn.c && gcc -c -Wreturn-type noreturn.c
noreturn.c: In function ‘foo’:
noreturn.c:1:1: warning: control reaches end of non-void function [-Wreturn-type]
int foo() { }
^~~
According to C How to Program (Deitel):
Standard library functions like printf and scanf are not part of the C programming language. For example, the compiler cannot find a spelling error in printf or scanf. When the compiler compiles a printf statement, it merely provides space in the object program for a “call” to the library function. But the compiler does not know where the library functions are—the linker does. When the linker runs, it locates the library functions and inserts the proper calls to these library functions in the object program. Now the object program is complete and ready to be executed. For this reason, the linked program is called an executable. If the function name is misspelled, it is the linker which will spot the error, because it will not be able to match the name in the C program with the name of any known function in the libraries.
These statements leave me doubtful because of the existence of header file. These files are included during the preprocessing phase, before the compiling one, and, as I read, there are used by the compiler.
So if I write print instead of printf how can't the compiler see that there is no function declared with that name and throw an error?
If it is as the book says, why can I declare function in header files if the compiler doesn't watch them?
So if I write print instead of printf how can't the compiler see that there is no function declared with that name and throw an error?
You are right. If you made a typo in any function name, any modern compiler should complain about it. For example, gcc complains for the following code:
$ cat test.c
int main(void)
{
unknown();
return 0;
}
$ gcc -c -Wall -Wextra -std=c11 -pedantic-errors test.c
test.c: In function ‘main’:
test.c:3:5: error: implicit declaration of function ‘unknown’ [-Wimplicit-function-declaration]
unknown();
^
However, in pre C99 era of C language, any function whose declaration isn't seen by the compiler, it'll assume the function returns an int. So, if you are compiling in pre-C99 mode then a compiler isn't required to warn about it.
Fortunately, this implicit int rule was removed from the C language since C99 and a compiler is required to issue a diagnostic for it in modern C (>= C99).
But if you provide only a declaration or prototype for the function:
$ cat test.c
int unknown(void); /* function prototype */
int main(void)
{
unknown();
return 0;
}
$ gcc -c -Wall -Wextra -std=c89 -std=c11 test.c
$
(Note: I have used -c flag to just compile without linking; but if you don't use -c then compiling & linking will be done in a single step and the error would still come from the linker).
There's no issue despite the fact, you do not have definition for unknown() anywhere. This is because the compiler assumes unknown() has been defined elsewhere and only when the linker looks to resolve the symbol unknown, it'll complain if it can't find the definition for unknown().
Typically, the header file(s) only provide the necessary declarations or prototypes (I have provided a prototype for unknown directly in the file itself in the above example -- it might as well be done via a header file) and usually not the actual definition. Hence, the author is correct in that sense that the linker is the one that spots the error.
So if I write print instead of printf how can't the compiler see that there is no function declared with that name and throw an error?
The compiler can see that there is no declaration in scope for the identifier designating the function. Most will emit a warning under those circumstances, and some will emit an error, or can be configured to do so.
But that's not the same thing as the compiler detecting that the function doesn't exist. It's the compiler detecting that the function name has not been declared. The compiler will exhibit the same behavior if you spell the function name correctly but do not include a prior declaration for it.
Furthermore, C90 and pre-standardization C permitted calls to functions without any prior declaration. Such calls do not conform to C99 or later, but most compilers still do accept them (usually with a warning) for compatibility purposes.
If it is as the book says, why can I declare function in header files if the compiler doesn't watch them?
The compiler does see them, and does use the declarations. Moreover, it relies on the prototype, if the declaration provides one, to perform appropriate argument and return value conversions when you call the function. Moreover, if you use functions whose argument types are altered by the default argument promotions, then your calls to such functions are non-conforming if no prototype is in scope at the point of the call. Undefined behavior results.
I read in the c99 Standard:
-remove implicit function declaration,
-remove implicit int.
But when I try to compile this code with gcc compiler in c99 mode using -pedantic
main(void){
f(3);
return 0;
}
int f(int a){
....
}
I expect 2 errors, but I just receive 2 warnings:
-warning: return type defaults to ‘int’
-warning: implicit declaration of function ‘f’.
Shouldn't them be errors in c99?
http://gcc.gnu.org/c99status.html
In both situations there's written "done".
Thanks.
The C standard requires a diagnostic for any translation unit containing a violation of a syntax rule or constraint. It does not require such diagnostics to be fatal; the compiler is free to continue processing the source file. The behavior of the resulting executable, if any, is undefined. The standard makes no distinction between warnings and fatal errors.
(The only thing that requires a compiler to reject a source file is the #error directive.)
Conclusion: when compiling C, take warnings very seriously.
I don't believe the compiler is required to produce a fatal error. Use -Werror if you're concerned...
Two points: first, it may (usually does) take a specific set of flags to get a compiler to conform with the standard.
Second, all that's required by the standard is that the implementation issue a "diagnostic" in the case of an error -- but it's up to the implementation to define what is or isn't a diagnostic. It's free to say a "warning" is a diagnostic if it wants to. When a diagnostic is issued, it may quit compiling, or it can compile the code anyway.
Bottom line: what it's doing is probably enough to conform, for whatever that's worth.
I use scanf in a c program to read an int from STDIN:
scanf("%d", &n);
when I compile the c program with optimization enabled I get some warnings:
gcc main.c -lm -lpthread -O2 -o main
main.c: In function ‘main’:
main.c:45: warning: ignoring return value of ‘scanf’, declared with attribute warn_unused_result
main.c:50: warning: ignoring return value of ‘scanf’, declared with attribute warn_unused_result
but when I remove the optimization options, why don't I get those warnings?
gcc main.c -lm -lpthread -o main
P.S: I'm not using -Wall or something similar.
Changing optimizer settings changes how much (and how) the compiler analyzes your code.
Some program flow analysis is not done when optimization is not enabled (or not set high enough), so the related warnings are not issued.
You'll see that frequently for "unused variable" warnings - these require analysis of the code beyond what is necessary to simply compile it, so you'll ususally only get them with optimization enabled.
(And you really should be compiling with -Wall.)
-Wunused-result is enabled by default: Because you'll actively need to decorate a function with __attribute__ ((warn_unused_result)) to trigger the warning, false positives only occur when it's used too liberally.
Even without passing additional flags, gcc should produce a warning. However, as Mat explained, the compiler doesn't do the necessary control flow analysis without increasing optimization levels.
Fix your code or silence the warning by adding -Wno-unused-result. Casting the return value to void will probably do as well.
To silence the warning in code, you'll need to assign the return value to a dummy variable, which you then can cast to void to avoid a new warning about the unused variable. It's also possible to substitute a C99 compound literal for the explicitly declared variable (tested with gcc 4.5.3).
This is indeed not optimal - I really expected the void-cast I originally porposed to work...
The following file foo.c is a simplified version of a subtler bug I found in my code.
int b;
void bar(int a);
void foo(int a)
{
bar(a);
a = 42;
}
The line a = 42 is in fact a typo in my code: I meant b = 42. I don't expect the compiler to detect that I made a typo, but I would like the get a warning that I am assigning to a local variable (or a function parameter) that is not going to be used anymore. If I compile this file with
% gcc-4.6 -Wall -Wextra -pedantic -O3 -c foo.c
I get absolutely no warning. Inspecting the generated code shows that the assignment a = 42 is not performed, so gcc is perfectly well aware that this instruction is useless (hence potentially bogus). Commenting the call to bar(a); does produce a warning warning: parameter ‘a’ set but not used [-Wunused-but-set-parameter], so it seems like gcc will not warn as long as a is used somewhere in the function, even if it is before the assignment.
My questions:
Is there a way to tell GCC or Clang to produce a warning for such case? (I could not get clang 3.0 to produce any warning, even with the call to bar removed.)
Is there a reason for the actual behavior? I.e, some cases were it is actually desirable to assign to local variables that will be thrown away by the optimizer?
There is no gcc or clang option to my knowledge that can warn about this useless assignment.
PC-Lint on the other hand is able to warn in this situation.
Warning 438 Last value assigned to variable 'Symbol' not used -- A value had
been assigned to a variable that was not subsequently used. The
message is issued either at a return statement or at the end of a
block when the variable goes out of scope.
The compiler will detect that this is dead code and optimise it out anyway. If you look at the assembly listing (provided you tell gcc to optimise), then you will find the assignment is non-existent.