Home > other >  Undefined behaviour when function return type is not int
Undefined behaviour when function return type is not int

Time:03-23

Consider snippet 1:

#include <stdio.h>

int main() {
    float val;
    val = fun(2, 4);
    printf("%f", val);
    
    return 0;
}
float fun(int x, int y){
    return x y;
}

Code snippet 2:

#include <stdio.h>

int main() {
    int val;
    val = fun(2, 4);
    printf("%d", val);
    
    return 0;
}
int fun(int x, int y){
    return x y;
}

In case of snippet 1, it gives me error, as follows:

gcc /tmp/1cUl25Ux4O.c -lm
/tmp/1cUl25Ux4O.c: In function 'main':
/tmp/1cUl25Ux4O.c:6:11: warning: implicit declaration of function 'fun' [-Wimplicit-function-declaration]
    6 |     val = fun(2, 4);
      |           ^~~
/tmp/1cUl25Ux4O.c: At top level:
/tmp/1cUl25Ux4O.c:11:7: error: conflicting types for 'fun'
   11 | float fun(int x, int y){
      |       ^~~
/tmp/1cUl25Ux4O.c:6:11: note: previous implicit declaration of 'fun' was here
    6 |     val = fun(2, 4);
      |           ^~~

But in case of second snippet, i'm getting correct output. (i.e 6).
In both the cases I've omitted function declaration and just the definition part is present, and that too after main(). But, if incase of snippet 1, if i change the order and define fun(int, int) before main(), i'm getting the desired output.(i.e 6.0000)
I'm not able to figure it out.

Why is this happening?
Is it due to the order in which functions are pushed into stack?
If that is the reason, then why code in snippet 2 is working?
Please provide me either with references/ explanation. Thanks!

Update:
In the error log for snippet 1, it says that there are conflicting types for fun. But there's just one fun(int, int) present in the code. What is creating conflict?

CodePudding user response:

First snippet:

int main() {
    float val;
    val = fun(2, 4);
    printf("%f", val);
    
    return 0;
}
float fun(int x, int y){
    return x y;
}

When you write val = fun(2, 4); in main the compiler has not yet encountered float fun(int x, int y). Therefore it assumes that fun is declared like this: int fun(); (function returning an int and taking any number of parameters of any type.

Then the compiler encounters float fun(int x, int y), but as explained in the preceeding paragraph, the compiler assumes now that fun returns an int, hence the conflict.

If you put float fun(int x, int y) before main, the compiler encounters float fun(int x, int y) and now knows that fun returns a float and takes exactly two int arguments.

Implicit declarations are a thing of the past, and they shouldn't be used nowadays ever.

BTW:

There is no undefined behaviour involved here. Undefined behaviour is something completly different.

I suggest you read this: Undefined, unspecified and implementation-defined behavior

CodePudding user response:

But in case of second snippet, i'm getting correct output.

No, it does not compile either. So save you from the head ache of troubleshooting code where the compiler has already found the bugs, ensure to use a conforming C compiler, see What compiler options are recommended for beginners learning C?

When using a correctly configured conforming C compiler, we get this error:

error: implicit declaration of function 'fun'

The reason why some compilers decide to generate an executable when not set to strict compliance mode is historical. 32 years old (ancient!) compilers had a feature called "implicit function declaration" and "implicit int". This meant that when the compiler encountered a function call to a function which had not yet been declared/defined, it guessed that the function would have a return type of int. Because why not - it could be the correct type in some cases!

And in case it isn't, we get undefined behavior and anything could happen. Such as the function returning a float but the caller treating the raw binary representation of that float as an int. Or the program crashing.

This language design flaw was removed from C in the C99 version released 23 years(!) ago.

There is probably no reason why you should be using ancient compiler modes, so just compile with the options given in the link above.

  • Related