I was just trying to see what would happen, if I use return 0 statement with void main(). I was expecting that the compiler would give an error but it just gave a warning and successfully executed the program but at last, returned some non zero value, now I have doubt why the program executes without an error and then also return some value when I have used void main()?
#include<stdio.h>
void main()
{
printf("Hello World\n");
return 0;
}
Using return 0; in a function that returns void is a constraint violation:
6.8.6.4 The return statement
Constraints
1 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.
C 2011 online draft
The compiler must issue a diagnostic for a constraint violation (the warning you saw during compilation) - however, the compiler may continue to translate the program and generate an executable (the difference between a warning and an error, and whether it halts translation, is up to the implementation).
Secondly, unless your compiler's documentation explicitly lists void as a valid return type for main, using void main results in undefined behavior - at that point, the compiler is not required to handle the situation in any particular way.
Usually, trying to figure out how you got a specific result from undefined behavior is a waste of time, since the behavior may not be repeatable. In this case, you told the compiler main wasn't going to return a value and it generated the machine code accordingly. It's likely that the register used for that return value was overwritten as soon as main returned.
i have doubt why the program executes without a error and then also return some value when i have used void main()
The C standard says that the right thing to do is int main, and that a conforming implementation is permitted to allow other signatures on main if it so chooses.
Apparently your implementation chooses to allow this non-standard usage, and that the behaviour it exhibits is a warning at compile time followed by the observed behaviour at runtime.
But you already knew that. The compiler does what the compiler does because the compiler authors wrote it that way. If you want to know why they made those choices, ask them. Since you have not said what compiler you are using, we have nothing more to go on.
Your code is not a valid C code. C language does not allow you to use return 0 in a void function. It is a constraint violation, i.e. what we colloquially call an error. Every conforming C compiler is required to issue a diagnostic message for this code, after which the behavior of your code is undefined from the point of view of standard C language.
According to your description, your compiler did issue a diagnostic message for this code, as required by the language specification. After that, whatever behavior you observed from the compiled code might (or might not be) defined by your specific compiler, but it is no longer defined by the language itself.
This return value of main is typically utilized the operating system where the program runs to determine if there was an error during execution or not, typically the value 0 is success and other values are interpreted as an error by convention.
Related
I have successfully compiled and executed the following code in GCC:
#include <stdio.h>
int foo()
{
}
int main()
{
int i = 12345;
i = foo();
printf("i is: %d", i);
}
The output is:
i is: 0
So GCC allowed me not to return from the function foo() and made foo() return 0.
Does this behavior only apply to GCC or do other C standards also have it (based on my understanding, GCC does not conform to any C standard)?
None of the C standards require the compiler to produce an error or warning if a function is missing a return statement¹.
In all of the C standards the behaviour is undefined if control flow reaches the end of non-void function without a return and the return value of the function is then used (as in your code).
So if by "allow" you mean "specify it as legal, well-defined behaviour", none of the C standards allow your code. If you just mean "don't require an implementation to produce an error", all of them do.
Do note that the value of i in your example program can easily change if you change the definition of foo (without adding a return). You can not rely on it being 0. There is no rule that says "if there's no return, return 0" - neither in the standard nor in GCC's implementation. According to the standard it's undefined and in GCC it will just be whatever happens to be in the return register at that time.
¹ In the general case this would be undecidable. One could do what e.g. Java does and define the rules so that some otherwise valid function definitions are rejected, but none of the C standards do this.
gcc does give a warning:
warning: control reaches end of non-void function [-Wreturn-type]|
(Disclaimer: I get different results from different versions of gcc. To be sure, compile with -Wall -Wextra -pedantic-errors.)
What happens in this case is not covered by the C standard. The standard merely says that (C11 6.9.1/12):
If the } that terminates a function is reached, and the value of the function call is used by the caller, the behavior is undefined.
In your case, the caller does use the return value by storing it in i. So this is undefined behavior - the behavior is not covered by the C standard and the compiler has no obligation to inform you about it. Anything could happen. So this should be regarded as a bug in most cases.
Well, there is nothing in the standard that stops you from writing illegal code. However, it does mention that this is undefined behaviour.
Quoting C11, chapter §6.9.1:
If the } that terminates a function is reached, and the value of the function call is used by
the caller, the behavior is undefined.
C89 states (at least in the draft):
If a return statement without an expression is
executed, and the value of the function call
is used by the caller, the behavior is undefined.
Which means it's legal to write code as you did. It's not an error.
It's undefined behavior, but it's syntactically legal. Since it's not specifically "illegal" and syntactically allowed a compiler adhering to C89 may very well just compile it and the result will be undefined... but it's a legit program as far as the compiler is concerned.
That's why even with -Wpedantic it's probably not going to be rejected. Undefined behaviour means exactly what it says: it's undefined what happens. Be aware that compilers may optimize undefined behaviour away completely (which is ok, because it's undefined behaviour anyway, so the compiler can do whatever it wants).
I think that in this case the undefined behaviour is pretty common between the most popular compilers. If you disassemble your foo function, you will find these instructions in almost every version of GCC:
push rbp
mov rbp, rsp
nop
pop rbp
ret
This code is doing nothing, exactly what you want. However, it is not even following the calling convention rules whenever a result from a function is expected. The result should be passed to the caller by the eax/rax register. In foo, this register is not even modified and this is the reason why you get undefined behaviour.
Omitting a return is like saying: "I do not want to follow the rules you gave me". Clang produces similar code and I guess other compilers (unless further options or optimizations are applied) reason in the same way. Nothing stops you from doing that, neither a compiler. Undefined behaviour is the price for this freedom.
The proof that the compiler puts its faith on the code written is that the eax/rax register is really considered as the store for the function's result. In your case eax is never used before in that code, and its last value is zero. But try with this:
int i = 12345;
int m = 12345;
m *= 3;
i = foo();
printf("i is: %d", i);
The output is probably going to be 37035 even if that's the m's value.
I have successfully compiled and executed the following code in GCC:
#include <stdio.h>
int foo()
{
}
int main()
{
int i = 12345;
i = foo();
printf("i is: %d", i);
}
The output is:
i is: 0
So GCC allowed me not to return from the function foo() and made foo() return 0.
Does this behavior only apply to GCC or do other C standards also have it (based on my understanding, GCC does not conform to any C standard)?
None of the C standards require the compiler to produce an error or warning if a function is missing a return statement¹.
In all of the C standards the behaviour is undefined if control flow reaches the end of non-void function without a return and the return value of the function is then used (as in your code).
So if by "allow" you mean "specify it as legal, well-defined behaviour", none of the C standards allow your code. If you just mean "don't require an implementation to produce an error", all of them do.
Do note that the value of i in your example program can easily change if you change the definition of foo (without adding a return). You can not rely on it being 0. There is no rule that says "if there's no return, return 0" - neither in the standard nor in GCC's implementation. According to the standard it's undefined and in GCC it will just be whatever happens to be in the return register at that time.
¹ In the general case this would be undecidable. One could do what e.g. Java does and define the rules so that some otherwise valid function definitions are rejected, but none of the C standards do this.
gcc does give a warning:
warning: control reaches end of non-void function [-Wreturn-type]|
(Disclaimer: I get different results from different versions of gcc. To be sure, compile with -Wall -Wextra -pedantic-errors.)
What happens in this case is not covered by the C standard. The standard merely says that (C11 6.9.1/12):
If the } that terminates a function is reached, and the value of the function call is used by the caller, the behavior is undefined.
In your case, the caller does use the return value by storing it in i. So this is undefined behavior - the behavior is not covered by the C standard and the compiler has no obligation to inform you about it. Anything could happen. So this should be regarded as a bug in most cases.
Well, there is nothing in the standard that stops you from writing illegal code. However, it does mention that this is undefined behaviour.
Quoting C11, chapter §6.9.1:
If the } that terminates a function is reached, and the value of the function call is used by
the caller, the behavior is undefined.
C89 states (at least in the draft):
If a return statement without an expression is
executed, and the value of the function call
is used by the caller, the behavior is undefined.
Which means it's legal to write code as you did. It's not an error.
It's undefined behavior, but it's syntactically legal. Since it's not specifically "illegal" and syntactically allowed a compiler adhering to C89 may very well just compile it and the result will be undefined... but it's a legit program as far as the compiler is concerned.
That's why even with -Wpedantic it's probably not going to be rejected. Undefined behaviour means exactly what it says: it's undefined what happens. Be aware that compilers may optimize undefined behaviour away completely (which is ok, because it's undefined behaviour anyway, so the compiler can do whatever it wants).
I think that in this case the undefined behaviour is pretty common between the most popular compilers. If you disassemble your foo function, you will find these instructions in almost every version of GCC:
push rbp
mov rbp, rsp
nop
pop rbp
ret
This code is doing nothing, exactly what you want. However, it is not even following the calling convention rules whenever a result from a function is expected. The result should be passed to the caller by the eax/rax register. In foo, this register is not even modified and this is the reason why you get undefined behaviour.
Omitting a return is like saying: "I do not want to follow the rules you gave me". Clang produces similar code and I guess other compilers (unless further options or optimizations are applied) reason in the same way. Nothing stops you from doing that, neither a compiler. Undefined behaviour is the price for this freedom.
The proof that the compiler puts its faith on the code written is that the eax/rax register is really considered as the store for the function's result. In your case eax is never used before in that code, and its last value is zero. But try with this:
int i = 12345;
int m = 12345;
m *= 3;
i = foo();
printf("i is: %d", i);
The output is probably going to be 37035 even if that's the m's value.
I'm working with a large C-only project, and I keep getting bitten by the following problem:
Lets say I have a function
void MyFunction(int parameter)
{
printf("parameter: %d\n", parameter);
}
Which normally gets called
int aVariable = 5;
MyFunction(aVariable);
However, apparently due to the C standard specifications, this does not cause a compilation error:
int aVariable = 5;
MyFunction(&aVariable); // No error signaled, but causes all sorts of mayhem
How can I catch this kind of error, specifically in Visual Studio? Is there any setting I can turn on to make it stricter?
Any strategy you might recommend (besides "don't make typos")?
Edit:
I might add that due to the (crappy) nature of the project, the sample code already generates tons of warnings; I am not sure I can remove all of them in the time I have. Generating more warnings might not be the best option -- however being able to discern about these specific warnings (as one answer suggests) might be the solution to this particular problem.
If the function MyFunction is declared with prototype before the point of the call, then
MyFunction(&aVariable);
is a genuine full-blown constraint violation in C, i.e. it is what we usually call "an error". That's what the language specification says. In other words, your belief that this is somehow allowed "due to the C standard specifications" is incorrect: this is explicitly disallowed by C standard.
Any C compiler will issue at least a warning for such code, which you should also pay attention to. If your C compiler does not report this violation as an error, it can usually be changed through compiler setup.
In case of Visual Studio compiler, one approach is to watch the warning number issued in such cases and ask the compiler to convert such warnings into errors. This can be done through either #pragma warning or through project settings.
Insert a function declaration of the form
void MyFunction(int parameter);
before attempting to call it. If you don't do that, when calling MyFunction() a C compiler is required to assume MyFunction() accepts a variable argument list (arbitrary number and types of arguments) and returns int.
Hence code will compile without error, even if the function is called with incorrect arguments or calling code attempts to use the return value (which should not be done with a void function). The result, if the arguments supplied do not match what the actual function definition expects, is often in the realm of undefined behaviour.
Declaring the function before calling it is good practice, and allows the compiler to detect a problem, and issue errors or warnings as needed. Without the declaration, some compilers do issue warnings, but not all compilers do.
This question already has answers here:
Checking return value of a function without return statement
(3 answers)
Closed 8 years ago.
So, I did some changes in this simple program for understanding purposes.
Here is the code:
#include<stdio.h>
add1(int a,int b){
int j = a + b; // Statement-1
int y = a - b; // Statement-2
}
void main() {
int result = add1(5,7);
printf("%d",result);
}
I know that the default return type of a C function is int and the default return value is return 0 if the function is main, else the return value is undefined if the function does return something. I know that it is not a good practice. But here are my observations:
The return value of add1 takes the value of the closest declared variable to the ending brace of the add1 function i.e in my code y. Hence, the output is -2. If I comment the statement-2 the output becomes 12.
So, is this what we call undefined behavior?
Yes. Once there is undefined behavior, result may comes out to be either expected or unexpected.
C faq - 11.33:
undefined: Anything at all can happen; the Standard imposes no requirements. The program may fail to compile, or it may execute incorrectly (either crashing or silently generating incorrect results), or it may fortuitously do exactly what the programmer intended.
C faq - 11.35:
A compiler may do anything it likes when faced with undefined behavior (and, within limits, with implementation-defined and unspecified behavior), including doing what you expect. It's unwise to depend on it, though.
Yes. §6.9.1 ¶12 of N1256 (C99) states:
If the } that terminates a function is reached, and the value of the function call is used by the caller, the behavior is undefined.
It appears that you are saying that your compiler appears to return the value of the last defined variable and are wondering whether that particular algorithm is what is meant by "undefined behavior." Actually the algorithm that a particular compiler uses, if any, to set a return value, in a way, doesn't really demonstrate notion of undefined behavior.
The right way to look at things is that the language specification allows a (conforming) compiler to generate code that does whatever it wants to set a return value (or crash or go into an infinite loop).
The fact that you appeared to have found that your compiler does some particular thing is actually somewhat irrelevant. It didn't have to do what you found it to do. It could have done something else.
Not that anyone asked, but what you are seeing is probably a result of what generally happens in C compilers: the value returned from a function is the value that happens to be held in a particular processor register when the function exits. It appears your compiler is targeting its computations directly into that special register. So yeah, the fact that you are seeing what you are seeing makes sense (at least to compiler writers).
But it doesn't have to be that way. The fact that it is that way simply agrees with the language requirement of undefined behavior, but it is not "what is meant by" undefined behavior.
Maybe this is just a nit-pick, but it reflects how I read the question.
f() does not return even though it's signature say it should.
Why is the reason for allowing this to compiling?
Is there a reason the C standard does not require the compiler to make it fail?
I know that it is Undefined behavior and all, but why is it allowed in the first place?
Is there a historical reason?
double f(){}
int main()
{
f();
return 0;
}
Is there a reason the C standard does not require the compiler to make
it fail?
By invoking undefined behavior, the C standard allowed the compilers to be less complicated. There is indeed some cases, such as if statements, in which it is hard to say whether the function returns a value or not:
int f(int n)
{
if (n > 0) return 1;
}
If I write f(5), it is easy for the compiler to say that the
function is correct.
If I write f(-5), it is also easy to detect
an undefined return value.
But if the argument comes from user input for example, how should the compiler be able to know whether the function returns a value? Since this could both a valid or a wrong program, C standard allows the compilers to do what they want. C is designed to be as smart and simple as possible.
The compiler could certainly analyze all code paths for the function and reject the program if it cannot prove that the function always returns a meaningful value. I suppose the reason the standard does not mandate it is that in the old days compilers were much less sophisticated than we work with today.
Of course using the return value of such a function is undefined behavior:
If the } that terminates a function is reached, and the value of the
function call is used by the caller, the behavior is undefined.
It's easy to tell that your function will reach the end without returning a value. It doesn't return and it doesn't call any code that could prevent it reaching the end (like abort()).
In fact your program does not have undefined behavior in C99, since the missing return value isn't used by the caller. 6.9.1/12:
If the } that terminates a function is reached, and the value of the
function call is used by the caller, the behavior is undefined.
So your code has questionable style, but is well-defined.
The C++ standard changes the rule and remarks on that change in [diff.stat]. It says that the C version of the rule is to support code that was written back in the days when C didn't distinguish between int return and void return. So the reason your code has defined behavior in the first place is "legacy". That said, AFAIK C has always distinguished between double return and int return, so it could probably have made it UB for a function returning double to fall off the end, had it been done at the right time.
Leaving aside whether the return value is used, consider a tricker function:
double f() {
if (g()) exit();
}
This function also contains no return statements, but doesn't reach the end of the function if in fact g always returns a true value or doesn't return at all. So this function should be accepted even if its return value is used, on the general C standard principle that you're expected to know what you're doing and mean what you say. If g is defined in a different TU then you probably know more about it than the compiler does.
Even if it weren't for the legacy reasons, I'm pretty sure that the standard simply cannot be bothered adding text in order to define what non-return scenarios compilers are required to detect. It's left to quality of implementation -- if it can be determined at compile time that your function cannot possibly avoid UB then maybe the compiler will warn anyway despite no diagnostic being required. For that matter, it will occasionally warn when behavior is defined on the general C implementer's principle that some things are so daft that no user could reasonably mean them.
Because the compiler can not tell if the function returns at runtime or not.