I have the following small C-programm (main.c):
#include <stdio.h>
int main() {
printf("bmi %.1f \n", bmi(85, 1.5f));
return 0;
}
float bmi(int weight, float height) {
return weight / (height * height);
}
Why does it compile without error? I expected that I need a prototype of the bmi()-function before the main().
When I debug the program, height is 0.0 not 1.5! What's going on?
Why does it compile without error?
The C language used to allow implicit declarations prior to the C99 standard, and VS defaults to that behavior. However, with the default settings, VS does issue the following warnings, which should not be ignored.
(4,30): warning C4013: 'bmi' undefined; assuming extern returning int
(4,12): warning C4477: 'printf' : format string '%.1f' requires an argument of type 'double', but variadic argument 1 has type 'int'
You can promote C4013 to an error (/we"4013") in which case the compilation will actually fail instead of issuing just a warning. In recent versions 16.8 and later compiling with /std:c11 should disable implicit declarations and always trigger an error (disclaimer: not tried).
When I debug the program, height is 0.0 not 1.5! What's going on?
At the point the compiler sees the bmi(85, 1.5f) call, it will assume the implicit function declaration int bmi(). In particular, it will assume the return value is an int so it will pass it as an int to printf. But the format string "%.1f" tells printf to expect a double argument (following the default promotion rules), so what happens next is undefined behavior.
Related
As expected following code generates an error if prototype double cubenum(); is not declared as required in C.
#include <stdio.h>
#include <stdlib.h>
int main()
{
printf("Answer is: %f", cubenum(3.0));
return 0;
}
double cubenum(double number){
double result = number * number * number;
return result;
}
Whereas if cubenum definition is above is replaced with following definition without return then it does not generate any error when cubenum prototype is not declared:
void cubenum(double number){
double result = number * number * number;
printf("Answer is: %f", result);
}
And when prototype is declared as void cubenum(); with above cubenum definition without return it generates following error:
||=== Build: Debug in xxx(compiler: GNU GCC Compiler) ===|
C:\xxx\main.c||In function 'main':|
C:\xxx\main.c|10|error: invalid use of void expression|
||=== Build failed: 1 error(s), 0 warning(s) (0 minute(s), 0 second(s)) ===|
Line 10 was when tested: printf("Answer is: %f", cubenum(3.0));
So, question is:
Why a function which does not have a return, prototype declaration is not required and if declared gives error in the above example?
GCC version info
gcc (MinGW.org GCC-6.3.0-1) 6.3.0
You have written your program in a way that is characteristic of very old C programs, dating to the 1980s or 1990s, before "prototyped" function declarations became preferred style. C compilers, to this day, bend over backwards to keep those very old programs working, preserving language features that they rely on, but that were never standardized or have been removed from the C standard since 1989.
Perfectly correct modern style for your first program would look like this:
#include <stdio.h>
double cubenum(double);
int main(void)
{
printf("Answer is: %f", cubenum(3.0));
return 0;
}
double cubenum(double number)
{
double result = number * number * number;
return result;
}
with a prototyped forward declaration of cubenum, double cubenum(double);
It's important to understand that double cubenum(); is NOT a prototyped declaration in C, but rather a declaration that says cubenum takes any number and type of arguments. If you wanted to specify that cubenum takes no arguments, you would have to write double cubenum(void); This is also why I changed int main() to int main(void).
When you leave the forward declaration out entirely,
#include <stdio.h>
int main(void)
{
printf("Answer is: %f", cubenum(3.0));
return 0;
}
double cubenum(double number)
{
double result = number * number * number;
return result;
}
the C compiler sees a call to cubenum with no previous declaration for it at all. This was common in those very old C programs I mentioned. They relied on a feature called implicit declaration that was part of the original C standard but removed from its 1999 revision (commonly known as "C99"). Basically, the compiler assumes that the programmer meant to write int cubenum(); above main, but lazily left it out. This means cubenum takes any number and type of arguments (NOT that it takes no arguments) and returns int. So, leaving main out of it for now, it's like you wrote
int cubenum();
double cubenum(double number) { ... }
and the compiler rejects the program because the definition of cubenum has a different return type from the (implicit) forward declaration. That part I think you already understood.
Now, when you change cubenum to return nothing, so your complete program is
#include <stdio.h>
int main(void)
{
printf("Answer is: %f", cubenum(3.0));
return 0;
}
void cubenum(double number)
{
double result = number * number * number;
printf("Answer is: %f", result);
}
the implicit function declaration is still int cubenum() and the prototype from the function definition is void cubenum(double). As another compatibility feature for those very old C programs, these are considered not to be conflicting return types, and the compiler accepts the program. This is because the type void was invented in the 1989 C standard. Programs written before then would have instead given cubenum no return type at all...
cubenum(number)
double number;
{
double result = number * number * number;
printf("Answer is: %f", result);
}
... which technically declares it to return int! Immediately post-C89, those programs got updated to give their functions with no return value the type void, but it was too much work to stop relying on implicit declarations for them at the same time, so compilers grew a special case where int foo() and void foo() are considered not to be in conflict.
(Incidentally, because of yet another backward compatibility consideration — "old-style function definitions", which you can see in the above code fragment — preferred style in C is to put the opening curly brace of a function definition on its own line, even if all other opening braces are "cuddled".)
And finally, when you do put void cubenum(); above main, only then is the compiler officially aware that cubenum returns nothing. When it does know that, it knows that printf("%f", cubenum(3.0)); is incorrect because it's using the nonexistent return value of cubenum, and it rejects the program for that reason.
You shouldn't be relying on any of these backward compatibility features in a new program. I see that you are using GCC, so set your compilation options to something like this:
-std=gnu11 -g -Og -Wall -Wpedantic -Wstrict-prototypes -Wold-style-definition -Werror
which will disable almost all of the backward compatibility features. (There are a whole lot more warning options and you may want to consider turning on more of them. -Wwrite-strings and -Wextra are particularly useful for new code IMNSHO.) (Do NOT use the hyper-conformant mode, -std=c11, until you know considerably more about what you are doing; it can break the system headers, and it enables the "trigraph" misfeature that you almost certainly don't want.)
Whereas if cubenum definition is above is replaced with following
definition without return then it does not generate any error when
cubenum prototype is not declared:
Because when you don't have explicit declaration for a function, some C compilers will do it implicitly. Normally, it gives int for both return type and arguments.
A good-enough compiler should inform you about implicit declaration.
It's dangerous, because compiler won't know the exact prototype of the function.So you may have a very unpredictable result.
And when prototype is declared as void cubenum(); with above cubenum
definition without return it generates following error:
This is another problem, since you try to printf the return value of a void function.
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?
The specific rule violated is C 2018 6.5.2.2 (Function calls) 6:
If the expression that denotes the called function has a type that does not include a prototype, the integer promotions are performed on each argument, and arguments that have type float are promoted to double. These are called the default argument promotions. If the number of arguments does not equal the number of parameters, the behavior is undefined.…
Since this is not a constraint, the compiler is not required to produce a diagnostic—the behavior is entirely undefined by the C standard, meaning the standard imposes no requirements at all.
Since the standard imposes no requirements, both ignoring the issue (or failing to recognize it) and diagnosing a problem are permissible.
I was testing a code and I don't understand why it prints "The higher value is 0".
This is the main function:
int main() {
double a,b,c;
a=576;
b=955;
c=higher(a,b);
printf("The higher value is %g\n", c);
return 0;
}
and in another .c I have this function:
double higher(double a, double b){
if (a>b)
return a;
return b;
}
NOTE: if I put higher() in main.c it works correctly, but in that way it tells me the higher value is 0. It also works if I cast the return in higer() like this:
return (int)b;
Is there a difference if a function that returns a double is in the same .c as main() or in a different one?
Compile with a C99 or C11 compiler and read the warnings. You are using the function without prototype.
Without a prototype, pre-C99 assumes a function to return int by default.
C99 and later, require a prototype.
Even without additional warnings enabled:
$ cat test.c
int main()
{
int i = f();
return 0;
}
int f(void)
{
return 1;
}
$ gcc -std=c11 test.c
test.c: In function ‘main’:
test.c:13:2: warning: implicit declaration of function ‘f’ [-Wimplicit-function-declaration]
int i = f();
Note that gcc will not warn if compiling -std=c90, but will if enabling warnings -Wall.
So, as higher() is expected to return an int, the value is converted to double by the assignment (the type of c is not changed).
And now for the funny part: undefined behaviour (UB, memorize this phrase!) due to different signature for call and implementation of the function.
What might happen is according to procedure call standard (PCS) and the application binary interface (ABI) - check Wikipedia. Briefly: higher itself returns a double. That is likely passed in a floating point CPU register to the caller. The caller, OTOH, expects the return value (due to the missing prototype) in an integer CPU register (which happens to hold 0 by chance).
So, as they apparently have misscommunication, you get the wrong result. Note that this is a bit speculatively and depends on the PCS/ABI. All to remember is this is UB, so anything can happen, even demons flying out of your nose.
Why use prototypes:
Well, you allready noticed, the compiler has no idea, if you call a function correctly. Even worse, it does not know, which argument types are used and which result type is returned. This is particlularily a problem, as C automatically converts some types (which you did encounter here).
As classical K&R (pre-standard) C did not have prototypes, all arguments to unknown functions were assumed int/double for scalar arguments on a call. The result defaults to int. (Long time ago, I might be missing some parts; I started some coding with K&R, messed up types (exactly your problem here, but without a clean solution), etc., threw it in a corner and happily programmed in Modula-2 until some years later I tried ANSI-C).
If compiling code now, you should at least conform to (and compile for) C99, better use the current standard (C11).
When compiling a C program in Visual Studio 2013 the following may produce different results:
#include <math.h>
void bar(void) {
double f = fabs(-1.0);
/* f is 1.0 */
}
and
void foo(void) {
double f = fabs(-1.0);
/* f is 0 */
}
and the same snippet without including math.h. When omitting the include, the compiler does not report an error and assumes fabs has the following signature int fabs().
Is there anyway to force the compiler to report this as an error or even a warning?
In older C standards if a function is used before it's declared then it's assumed to receive an unknown number of arguments (under default promotion like in variadic functions such as printf) and return int. The compiler will expect the symbol to be fixed later during linking stage so no errors should be reported
So without including math.h the compiler doesn't know the prototype of fabs and will assume that it accepts any kinds of parameters and returns int. Then when linking the linker really found a symbol with the expected name and resolves to that function, but due to the mismatch in the function signature the behavior is undefined. Turn on all warnings and you'll see something about implicit return type
In VS2013 I got the below warning even without increasing the warning level
Warning 1 warning C4013: 'fabs' undefined; assuming extern returning int
For more information read
Why can I call a function in C without declaring it but not in C++?
Can we call functions before defining it?
Implicit declaration in C language
Are prototypes required for all functions in C89, C90 or C99?
Why the error of - calling the function before being declared, is not shown?
C language - calling functions without function prototype
This question already has answers here:
Getting "conflicting types for function" in C, why?
(11 answers)
Closed 4 years ago.
#define RAND_MAX 10
#include<stdio.h>
int main()
{
double x;
x=randRange(-1.0,1.0);
printf("x value is %f::",x);
return 0;
}
double randRange(double min, double max)
{
return rand() * (max - min) / RAND_MAX + min;
}
Error::The snippet below is the error being generated--
$gcc main.c -o demo -lm -pthread -lgmp -lreadline 2>&1
main.c:11:8: error: conflicting types for 'randRange'
double randRange(double min, double max) {
^
main.c:6:5: note: previous implicit declaration of 'randRange' was here
x=randRange(-1.0,1.0);
^
Error in conflicting types??I have checked return types.
You need to declare the function above the point where it is called.
double randRange(double min, double max);
int main()
{
double x;
x=randRange(-1.0,1.0);
...
double randRange(double min, double max)
{
If you don't, ansi C gives you an implicit declaration for a function returning int
It's because you use randRange before it's defined. Either move the definition to be above where you use it, or create a prototype (declaration) before.
Functions which are not declared when you call them default to return int. This default declaration is what is meant by the "implicit declaration" in the error message.
Your implicit declaration of randRange declares it as int (*)(float, float).
Always pre-declare functions to avoid this kind of errors. Just put
double randRange(double min, double max);
above your main.
You must be using an "old" C compiler (or running a modern compiler in "old" C89/90 mode). In a compliant modern C compiler (C99 and later) your code would typically fail to compile even earlier, at the point of the first call to randRange, since you are trying to use randRange function before it is declared. This is illegal in modern C.
In old C (C89/90) calling an undeclared function is legal. An attempt to call randRange as randRange(-1.0,1.0) makes the compile to implicitly conclude that it must be a function that has two double parameters and returns int. If your function is actually defined differently, then the behavior of your program is undefined.
This is exactly what happened in your case. Except that your compiler decided to "go an extra mile" and reported an error for a function with this sort of implicit declaration conflict (instead of quietly generating a program whose behavior is undefined).