venugopal
venugopal

Reputation: 273

C void function with return value

As far as I know, return statement in void function will throw an error.

But in the below program that is not the case.

Here the displayed output is 1. How comes?

main()
{
    int i=5;
    printf("%d",fun(fun(fun(i))));
}

void fun(int i)
{
    if (i%2)
    {
        return (i+(7*4)-(5/2)+(2*2));
    }
    else
    {
        return (i+(17/5)-(34/15)+(5/2));
    }
}

Upvotes: 5

Views: 3229

Answers (3)

Alexis Wilke
Alexis Wilke

Reputation: 20720

Because C is compiled to binary, technically, functions always return a value. With most modern processors, the returned value is saved in a register¹, such as RAX (or EAX in 32 bit) on an Intel processor, and you just can't remove a register from your CPU.

When you create a void function, the compiler will ignore the result, but it is still there.

In your case, the fun(fun(fun(i)))² expression will pass i to the first call, then, on an Intel processor on Linux, it will do MOV RDI, RAX for the second and third calls. These simply copy the result in RAX to the first parameter of the fun() function which in assembly is RDI.

So this is why your code does something. However, today it is considered Undefined Behavior. In the old days, when you could make your software work, it was considered a success. Any code that compiled was considered valid code...


¹ On some processors, especially some old 8 bit CPUs, a specific memory location may be used or the caller had to pass an address where the return value had to be written.

² Assuming your C compiler accepts such, which it shouldn't. At least gcc 11.3 refused to compile that code.

Upvotes: -2

Keith Thompson
Keith Thompson

Reputation: 263237

A return statement with no expression:

void func(void) {
    return;
}

is perfectly legal in a void function. The legality of a return statement with an expression depends on the version of the C language you're using.

The 1990 C standard says:

A return statement with an expression shall not appear in a function whose return type is void.

The 1999 and 2011 editions of the standard both say:

A return statement with an expression shall not appear in a function whose return type is void. A return statement without an expression shall only appear in a function whose return type is void.

This is a constraint, meaning that a compiler must issue a diagnostic (possibly a non-fatal warning) for any program that violates it.

C90 permitted a return statement with no expression in a non-void function for historical reasons. Pre-ANSI C did not have the void keyword, so there was no way to define a function that didn't return a value. Programmers would omit the return type (which would default to int) and simply ignore it. The C90 rule allowed such old code to compile without error. You could still fail to return a value from a non-void function; the program's behavior is undefined if a caller attempts to use the (nonexistent) result. The 1999 standard tightened up the rules a bit.

Another problem with your program is that you call fun before its declaration is visible. Under C99 and later rules, this is illegal (though a compiler might merely warn about it). Under C90 rules, this is legal, but the compiler will assume that the function returns int. Your program's behavior is undefined, but your void function fun might happen to behave as if it returned a value, and a call to it might happen to behave as if it used that value.

C compilers tend to be fairly lax about some errors, so that old code (sometimes written before the first actual standard was published) will not be rejected. But your compiler should have at least warned you about the return statement, and probably about the invalid call. You should pay close attention to compiler warnings; they should be treated almost the same way as fatal errors. And you should use options to increase the number of things your compiler warns you about. If you're using gcc, use -std=c90, -std=c99, or -std=c11, along with -pedantic to enforce standard conformance. You can add -Wall-Wextra` to enable more warnings.

Upvotes: 7

Bill Lynch
Bill Lynch

Reputation: 81926

The code you've presented is actually invalid in C99 for a variety of reasons, but the most painful one is below:

foo.c:5:17: warning: implicit declaration of function 'fun' is invalid in C99 [-Wimplicit-function-declaration]
    printf("%d",fun(fun(fun(i))));
                ^
foo.c:8:6: error: conflicting types for 'fun'
void fun(int i)
     ^
foo.c:5:17: note: previous implicit declaration is here
    printf("%d",fun(fun(fun(i))));
                ^

Note that if you gave a function prototype for fun(), which you really should, then you would get a different set of errors:

foo.c:7:25: error: passing 'void' to parameter of incompatible type 'int'
    printf("%d",fun(fun(fun(i))));
                        ^~~~~~

Upvotes: 4

Related Questions