While fiddling about old strange compatibility behaviors of C, I ended up with this piece of code:
#include <stdio.h>
int f();
int m() {
return f();
}
int f(int a) {
return a;
}
int main() {
f(2);
printf("%i\n", m());
}
I'm sure that the call to f()
in m()
is an undefined behavior as f()
should take exactly one argument, but:
- on x86, both GCC 9.1 and clang 8.0.1 do not show any warning (nor in
-Wextra
,-Weverything
or whatever) except when using GCC and-O3
. The output is then 2 without-O3
, 0 with it. On Windows, MSVC doesn't print any error and the program outputs just random numbers. - on ARM (Raspberry Pi 3), GCC 6.3.0 and clang 3.8.1, I observe the same behavior for errors, the option
-O3
still outputs 0, but normal compilation leads to 2 with GCC and... 66688 with clang.
When the error message is present, it's pretty much what you would expect: (pretty funny as a
is not present in the printed line)
foo.c: In function ‘m’:
foo.c:4:9: warning: ‘a’ is used uninitialized in this function [-Wuninitialized]
return f();
^~~
foo.c: In function ‘main’:
foo.c:11:2: warning: ‘a’ is used uninitialized in this function [-Wuninitialized]
printf("%i\n", m());
My guess is that -O3
leads GCC to inline the calls, thus making it understand that a problem occurs; and that the leftovers on the stack or in the registers are used as if they were the argument to the call. But how can it still compile? Is this really the (un)expected behavior?