warnings when activating the optimization options - c

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

Related

Rules for upconverting/downconverting types

Are there any rules at a function-level for what numeric types are allowed to be passed to it without a warning? For example, if we take the following two functions:
void take_int(int n){};
void take_double(double n){};
And calling it as:
take_int(4); # as intended
take_double(4.0); # as intended
take_double(4); # have to up-convert int to double
take_int(4.0); # have to down-convert double to int
When would this raise a warning or not be acceptable (ignoring what the actual function does with the values)?
The code you wrote is valid C, so it should be accepted by any compiler.
I tried your code in some recent versions of clang and GCC using Compiler Explorer, with the -Wall -Wextra --pedantic warning options, and none of them gave warnings.
However, the C standard does not specify what warnings a compiler should give, so the warnings you get will depend on what specific compiler you are using, and what version.

How do I make the compiler warn me about missing return value?

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() { }
^~~

why c doesn't check for return statements at compilation

I have started learning c. If a function is not called why compiler doesn't catch it as an error.
int foo(){}
void main(){}
I know it is a silly thing but could not figure it out.
If a function isn't called, that function will be doing nothing, and won't hurt to sit there. Also, sometimes you want to make libraries of functions, and these will not be called from anything in the compiled code, but may be called from other executables or libraries. The compiler will not know anything about this at compile-time.
There's probably a warning you can switch on on your compiler though.
You compiler doesn't know that your function isn't used, so it can't warn you about it. It's possible that in another file you declare this function and use it. The linker would then resolve it to this file after compilation.
On the other hand, if you enable warnings (e.g. by passing -Wall to the compiler), it will warn you of possible problems whenever possible.
For example if I compile your code with clang -Wall yourcode.c I get :
yourcode.c:1:11: warning: control reaches end of non-void function [-Wreturn-type]
int foo(){}
^
yourcode.c:2:1: warning: return type of 'main' is not 'int' [-Wmain-return-type]
void main(){}
^
yourcode.c:2:1: note: change return type to 'int'
void main(){}
^~~~
int
2 warnings generated.
So as you can see, the compiler will tell you if you forget a return or write a bad main, as long as you enable warnings. But with the code you posted, it can't tell you about functions that aren't used.
If you want the compiler to warn you about unused functions, you should declare those functions static, this will mean that those functions will only be usable in the file where they are defined. Then the compiler can tell you if you don't use it and you'll get a warning like this one :
yourcode.c:1:12: warning: unused function 'foo' [-Wunused-function]
static int foo(){}

How to get warnings about variables assigned to, but not used anymore?

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.

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

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.

Resources