What does void function in C return? - c

#include <stdio.h>
void main()
{
int k = m();
printf("%d", k);
}
void m()
{
printf("hello");
}
Output
hello5
What is the void function returning here?
If there is no printf() then the output is 1.
What is happening here?

A void function does not return anything. Your program invokes undefined behavior because it implicitly defines m to have return type int (in C89, if a function is called before it is declared, it's implicitly assumed to have return type int), but then defines it with return type void.
If you add a forward-declaration for m, the compiler will correctly complain that you're trying to use the return value of a void function, which is not possible.

In both cases (void m with caller expecting int, void main with caller-in-C-library expecting int), this is undefined behavior, and your compiler should have chewed you out, e.g. [GCC 4.8 with -Wall]:
test.c:3:6: warning: return type of ‘main’ is not ‘int’
void main()
^
test.c: In function ‘main’:
test.c:7:5: warning: implicit declaration of function ‘m’
int k = m();
^
test.c: At top level:
test.c:13:6: warning: conflicting types for ‘m’
void m()
^
test.c:7:13: note: previous implicit declaration of ‘m’ was here
int k = m();
^
"Implicit declarations" exist only for backward compatibility with pre-C1989 programs, which are more than 20 years out of date at this point. If you had written this code in a more modern style you would've gotten a hard error:
#include <stdio.h>
extern void m(void);
int main(void)
{
int k = m();
printf("%d", k);
return 0;
}
void m(void)
{
printf("hello");
}
⇒
test.c: In function ‘main’:
test.c:7:13: error: void value not ignored as it ought to be
int k = m();
^
The key addition is the extern void m(void); line. The compiler isn't allowed to look ahead to the definition of m when it checks main for errors, so you need a forward declaration to tell it what m's type really is. You should also know that in C (but not C++), void m() means "m takes an unspecified number of arguments". To declare a function taking no arguments, which is what you wanted, you have to write void m(void).
I believe what is happening on your specific system is that the return value of printf, which your code officially ignores, is being left in the return-value register and thus interpreted as the return value of m, but you cannot rely on anything predictable happening. That is what 'undefined behavior' means.

This is undefined behavior.
The reason the compiler lets you do the assignment is that there is no prototype of m available to it. When this happens, C standard says that the function must return int. Since in this case the actual function return type is void, the behavior is undefined. The value that you get in variable k is entirely arbitrary.

The return value of a function usually stored in the one of the CPU registers, EAX for x86. As C it just a friendly assembler, you can always read the value from the register. And you will get whatever was there. Efficiently, int k = m() tells program to store value of register EAX in the variable k.

You have not declared void m(); before calling it in main.
Some compilers assume the return type of unknown function symbols as int (unknown at the time of compilation of course) . In fact, your compiler has probably issued a compilation warning on this.
If you declare this function before main (where it should be declared), then you will probably get a compilation error.

Related

Why is this not giving compile error

#include <stdio.h>
int main()
{
int i = 10;
int *const p = &i;
foo(&p);
printf("%d\n", *p);
}
void foo(int **p)
{
int j = 11;
*p = &j;
printf("%d\n", **p);
}
p is a constant pointer to a variable x and can't point to other variables. But why don't we get error here and the output is 11 11?
This code doesn't violate a constraint, so the only thing you could expect from a compiler is a warning, which e.g. gcc gives you:
constptr.c: In function ‘main’:
constptr.c:6:9: warning: implicit declaration of function ‘foo’ [-Wimplicit-function-declaration]
foo(&p);
^
constptr.c: At top level:
constptr.c:9:10: warning: conflicting types for ‘foo’
void foo(int **p)
^
constptr.c:6:9: note: previous implicit declaration of ‘foo’ was here
foo(&p);
^
If you have a close look at these warnings, you see it's about an implicit declaration: foo() doesn't have a prototype before it is used, this isn't allowed by newer C standards, but compilers still support it for backwards compatibility. In that case, the compiler assumes the prototype is int foo(int). That's the reason for the next warning (conflicting types for foo).
If you correctly introduce a prototype like this:
#include <stdio.h>
void foo(int **p);
int main()
{
int i = 10;
int *const p = &i;
foo(&p);
printf("%d\n", *p);
}
void foo(int **p)
{
int j = 11;
*p = &j;
printf("%d\n", **p);
}
You get the warning one would expect:
constptr.c: In function ‘main’:
constptr.c:7:13: warning: passing argument 1 of ‘foo’ discards ‘const’ qualifier from pointer target type
foo(&p);
^
constptr.c:2:10: note: expected ‘int **’ but argument is of type ‘int * const*’
void foo(int **p);
^
So now the compiler warns you about the conversion dropping the const. C doesn't force you to write correct code, but you should anyways -- the warning tells you your code is incorrect and might invoke undefined behavior (as is the case here).
Although not related to your question, your code contains an even nastier case of undefined behavior: your last line in main() (the printf() line) dereferences a pointer that now points to an object of automatic storage duration (aka: the local variable j) that has gone out of scope and therefore doesn't exist any more!. It's unlikely that your compiler can warn you about this, still it's a recipe for desaster. So, always be very careful when writing C code.
Adding a very generic piece of advice here: Questions like this are often asked by people used to "modern" programming languages that are completely defined (e.g. Java, C#, and a lot more): Your code is either correct (and defined) or wrong and if it is wrong, you get either compilation errors or runtime exceptions. That's not how C works! In C, any code that adheres to the C grammar and doesn't violate a language constraint can be compiled and a lot of errors just lead to undefined behavior (which means anything could happen when executing that code). This means C "trusts" the programmer to do the correct thing -- the advantage is the possibility to create quite efficient native machine language code from a C source file, the downside is you're responsible yourself to make sure your code is actually correct. A best practice to start with is to always enable any warnings your C compiler gives you (a good setting for gcc would be e.g. -std=c11 -Wall -Wextra -pedantic) and always fix any warnings that come up.
Apart from the "modifying something const"-thing, the code as-is should actually compile with errors or warnings as the call of foo without having "forward-declared" it lets the compiler assume a different prototype (i.e. int foo(int)) than the actual definition then provides (i.e. int foo(int**); this could lead to "conflicting types for foo" - warning/error or something similar).
After having fixed this, with the following code, you should at least get a compiler warning (if not, turn on warnings or get a better compiler):
void foo3(int **p);
int main()
{
int i = 10;
int *const p = &i;
foo3(&p); // passing int * const * to parameter of type int ** discards const qualifiers
printf("%d\n", *p);
}
void foo3(int **p)
{
int j = 11;
*p = &j;
printf("%d\n", **p);
}
Thereby you get undefined behaviour because of modifying a constant value (even if the compiler does not give you an "error").
BTW: accessing a pointer that points to a (local) object which's lifetime has ended (as you do with *p = &j and the printf in main) is undefined behaviour.

function cast leads to gcc abort command

in the following code in file func.c:
#include <stdio.h>
int Myfunc1(int i, int z)
{
return i;
}
int main()
{
int ans;
/* casting the function into an 'int (int)' function */
ans = ((int(*)(int))(Myfunc1))(5);
printf("ans: %d\n\n", ans);
return 0;
}
i tried to cast an int(int,int) function into an int(int) function an got the gcc warning and note:
func.c:13:32: warning: function called through a non-compatible type [enabled by default]
func.c:13:32: note: if this code is reached, the program will abort
and when trying to run i get:
Illegal instruction (core dumped)
but if i compile this file with a .cpp ending with the gcc compiler it works OK.
can anyone explain the problem of the compiler in the .c case?
GNU GCC recognises all of the following as C++ files, and will use C++ compilation regardless of whether you invoke it through gcc or g++: .C, .cc, .cpp, .CPP, .c++, .cp, or .cxx
From https://stackoverflow.com/a/1546107/1767861
In that case, gcc compiles it in c++, which seems to accept the cast. Why is that ? See https://stackoverflow.com/a/559671/1767861
The problem is your signature for Myfunc1 and the function pointer you try to cast it to are of incompatible types. Instead, you need to do this:
ans = ((int(*)(int, int))(Myfunc1))(5, 5);
The link Thomas Ruiz posted explains why it is undefined behavior.
In summary:
Annex J.2
The behavior is undefined in the following circumstances:
-- A pointer is used to call a function whose type is not compatible with the pointed-to type (6.3.2.3).
6.3.2.3/8
A pointer to a function of one type may be converted to a pointer to a
function of another type and back again; the result shall compare
equal to the original pointer. If a converted pointer is used to call
a function whose type is not compatible with the pointed-to type, the
behavior is undefined.
#include <stdio.h>
int Myfunc1(int i, int z)
{
return i;
}
int main()
{
// define a function pointer and initialize it to NULL
int (*ans)(int, int) = NULL;
// get function pointer from function 'Myfunc1'
ans = Myfunc1(5, 6);
// call function using the pointer
printf("ans: %d\n", (*ans));
return 0;
}

function doesn't display the return value?

Why it doesn't return any value?
The output should be 155 but it always display 0. why?
int main()
{
int i=5;
printf("%d",fun(fun(fun(fun( fun(i))))));
return 0;
}
void fun(int i)
{
if(i%2) return (i+(7*4)-(5/2)+(2*2));
else return (i+(17/5)-(34/15)+(5/2));
}
But if I change
void fun(int i) // It doesn't work, case 1
to
int fun(int i) //It works fine, case 2
If fun doesn't return any value in case 1 ( void fun(int i) ), then how come
fun(fun(fun(fun( fun(i)))))); this statement is working?
Case 1 is undefined behavior, if we look at the C99 draft standard section 6.8.6.4 The return statement says(emphasis mine):
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
but if you do not have a declaration then most likely the compiler is implying the return type as int but then there is a mismatch between the declaration and implementation, this as far as I can tell then become undefined behavior again. I am able to run this on the latest gcc with the same result but I do receive the following warnings:
warning: implicit declaration of function 'fun' [-Wimplicit-function-declaration]
warning: conflicting types for 'fun' [enabled by default]
You have no declaration for your fun function at the time it is called so the compiler implicitly put a declaration with int return value.
In C89 if there is no visible declaration, it is as if the declaration:
extern int fun();
appeared before the function call. But as your function definition actually has void return value, your program invokes undefined behavior.
In C99, the rule for implicit function declaration has been removed and a diagnostic has to be issued.
EDIT: Actually as stated by #Shafik Yaghmour you are also having a return statement in a void function. This is a constraint violation in C89 (and C99 / C11) and the compiler has the right to stop the translation.
Both answers provided so far (by Shafik and ouah) are correct and complementary (and +1). But I want to stress something once more: do not ignore the warnings that a compiler gives you. Warnings in C can often save you from a lot of trouble.
When you compile your code (e.g. in gcc), you will see:
warning: ‘return’ with a value, in function returning void
This plainly says that you have a function that shouldn't return anything and, still, you're trying to return an integer from it. As the result type is explicitly declared to be void, the compiler chooses simply to ignore whatever you return; this appears as if you always return zero. This may seem strange but, as what you're doing is undefined behavior, the compiler is entitled to do so.

In my code, why is lack of a function declaration a non-issue for one function, but throws a warning for another?

In the following program,I use two functions prd() and display().I have declared neither of them ahead of main() before invoking them in main(),and I have defined both after main().Yet while prd() works smoothly inside main(),invoking display() shows the warning " previous implicit declaration of 'display' was here ".What is different about display() that there is a warning for it but not for the other funciton prd()?I have declared neither of them to begin with.Still there is warning due to invocation of one, but other one works fine.
#include<stdio.h>
int main()
{
int x=8,y=11;
printf("The product of %d & %d is %d",x,y,prd(x,y));
display();
return 0;
}
int prd(int x,int y)
{
return x*y;
}
void display()
{
printf("\n Good Morning");
}
PS: And I would really appreciate if you can answer this secondary question --"Is function declaration not necessary at all in C provided there is a definition for it?".I have the habit of declaring all functions of the program before the main() function, and then defining them after the main() function.Am I wrong?
When you use undeclared display() the compiler implicitly declares it as if it were returning int.
When the compiler finally sees the definition of display(), it sees that the return type is void, but it's already assumed it be int and so the definition and the implicit declaration differ, hence the error/warning.
The error occurs because C considers all non-initiated functions with a return type of int. Your display function is later defined with void return type.
Changing the return type of display() to int removes the warning.
By default, compiler assumes non-declared functions as returning int.
This is true for your prd function, but it does not match with display() as its void. This causes compiler to raise a warning.
For 2nd, its always appropriate to declare functions.

Function pointers assignment

Following the question Function pointer in Visual Studio 2012 I've started to wonder about the legality of certain assignments to function pointers in C.
The code below compiles with a warning, like I would expect because the assigned function requires more parameters than the function pointer declaration describes (GCC 4.8):
#include <stdio.h>
int test(int x, int y)
{
printf("%d", x);
printf("%d", y);
return 0;
}
int main()
{
int (*test_ptr)(int);
test_ptr = test;
test_ptr(1);
return 0;
}
Same warning appears if changing the code so that assigned function requires less parameters (GCC 4.8). Again, this is expected.
However, the following code compiles without a single warning, although the assigned function needs 2 parameters instead of 0 (GCC 4.8):
#include <stdio.h>
int test(int x, int y)
{
printf("%d", x);
printf("%d", y);
return 0;
}
int main()
{
int (*test_ptr)();
test_ptr = test;
test_ptr();
return 0;
}
No castings are involved anywhere.
Can anyone explain this compiler behavior?
The following:
int (*test_ptr)();
takes an unspecified number of parameters, not zero parameters.
For the latter, write
int (*test_ptr)(void);
P.S. Calling a two-argument function with zero arguments leads to undefined behaviour.
Converting from function pointer to function pointer is legal. What is illegal is calling a function pointer with a type that is not compatible with the actual pointed function.
C99 6.3.2.3 par. 8:
A pointer to a function of one type may be converted to a pointer to a
function of another type and back again; the result shall compare
equal to the original pointer. If a converted pointer is used to call
a function whose type is not compatible with the pointed-to type, the
behavior is undefined
If your compiler warned exactly for undefined behavior, it should warn at test_ptr();. But compilers cannot be expected to warn for all undefined behaviors or to warn only for undefined behaviors.
This static analyzer (that others and I work on) does its best to warn on all undefined behaviors and only for undefined behaviors. A lot of compromises are involved, but in this particular case:
$ cat > fp.c
int test(int x, int y)
{
printf("%d", x);
printf("%d", y);
return 0;
}
int main()
{
int (*test_ptr)();
test_ptr = test;
test_ptr();
return 0;
}
$ frama-c -val fp.c
...
fp.c:13:[value] warning: Function type must match type at call site: assert(function type matches)
Line 13 is test_ptr();.

Resources