How can this c++ function return anything? - c++

The following function does not have a "return grade", only return 0, yet it works and returns grade perfectly. How can this be?
int Grade(double points)
{
int grade = floor(0.25*points - 1.5);
if (grade < 0)
return 0;
}

How can this be?
Either the function returns 0, when grade is less than zero (after modification), or the behaviour of the program is undefined when grade is not less than zero. If function returns non-void, then it must not end without a return expression, or there will be UB.

Having a code path which does not return a value is clearly undefined behavior here, so the question is how can undefined behavior possibly return the correct value here? Presumably, there ought to be a return grade; at the end of the function.
One possibility is how values are returned from a function. On x86 systems, an int return value would typically be placed in the EAX register before the function returned. Other architectures may use different register names, but putting a return value in a register is pretty common.
It's likely that the line which computes the value of grade in the first place left the value of grade in the EAX register. Or, perhaps, the line which compares grade to 0 loads it into the EAX register. In either case, when the function returns, it would happen to have the correct value in EAX. If you really want to know what it's doing, have the compiler generate an assembly listing or step through the code with a debugger at the assembly language level.
Undefined behavior means the code can technically do anything. Which means that sometimes it does the (apparently) right thing.

Related

What is the difference between return the function and not return in a recursive function?

I wrote a simple binary search function in C++. The code is like below:
int binary_search(int arr[], int key, int imin, int imax)
{
if (imin > imax)
{
return -1;
}
else
{
int imid = imin + (imax - imin) / 2;
if (arr[imid] > key) binary_search(arr, key, imin, imid - 1);
else if (arr[imid] < key) binary_search(arr, key, imid + 1, imax);
else return imid;
}
}
But I found that if I add return in lines 10 and 11, the code seems work in the same way. The code is like below:
int binary_search(int arr[], int key, int imin, int imax)
{
if (imin > imax)
{
return -1;
}
else
{
int imid = imin + (imax - imin) / 2;
if (arr[imid] > key) return binary_search(arr, key, imin, imid - 1);
else if (arr[imid] < key) return binary_search(arr, key, imid + 1, imax);
else return imid;
}
}
So my question is what is the difference between these two situation?
Any function that does not return nothing (void) must encounter a return statement before running out of things to do. This is quite simply because there is no magic "return X if I do not return something" imperative, and the person using the function might rely on the return that you promised (but failed to deliver).
If you now follow the path that leads to those recursive calls in the original function, you will see that the call that initiated the recursive call in the first place now has to return something. Instead it simply ignores the result of the recursive call and runs out of things to do.
This causes something called undefined behavior, because C++ does not know what the heck you expect it to do. In fact, "it is legal for it to make demons fly out of your nose.", although it will usually - out of the pure benevolence of its soul - restrict itself to crashing horribly and unpredictably.
Two primary options exist why you do not see a difference:
The code is compiled in such a way that its undefined-ness will work as intended. You must not rely on this, ever. In practice, your code will be compiled in such a way that a single register holds your return value (RAX). Since the recursive call is the last thing your code does, that register may not be modified again, causing the code to act as if you had returned the result of the recursive call.
Your test cases never actually do a recursive call. This is technically legal, as the correctness of your program depends on its behavior at runtime. You should not rely on this either.
If you are interested, the relevant part of the standard is [stmt.return]/2, which says:
[...] Flowing off the end of a function is equivalent to a return with no value; this results in undefined behavior in a value-returning function.
"Flowing" refers to control-flow, and a "value-returning function" is any function that has a return type other than void.
If a function that returns non-void "falls of the end" (i.e. with no return statement) and the caller uses the return value, then the result is undefined behaviour. That is happening in your first version (either on your recursive calls, or for the caller) unless - by chance - your test case only ever results in the return imid statement being executed.
Unfortunately, one possible result of undefined behaviour is code that appears to work correctly for all your test cases. There is nothing preventing that. Program crashes (or other abnormal program terminations) are what people are often more acquainted with when undefined behaviour occurs, but a more insidious result of undefined behaviour is code that seems to behave as if nothing is wrong.
In practice, the reason your first case seems to work correctly is blind luck. For historical reasons that I won't expand on, a fair few compilers place working data for calculations (i.e. statements in your function) and results into machine registers, doesn't bother to clear those registers, and also (when a function returns int or other non-struct types) uses those same machine registers to hold return values from functions. So you can get lucky that the code in the first example behaves like the second. The problem is, however, that such behaviour is not guaranteed by the standard, may change between compilers, may change with compiler settings (e.g. optimisation options), and may even change when your compiler is upgraded at some future time.
The recursion will end eventually by actually executing a return statement. At that point, the compiler will place the returned value in the location used for return values.
When you get back to the calling function, without executing any other return statements, it just happens to still be there. Just by chance.

is this compiler optimization in context of recursion?

I was writing factorial using tail recursion and I have a question here. My original function looks like this
Code snippet A
#include <stdio.h>
int main(void)
{
int n = 0;
printf("Enter number to find factorial of : ");
scanf("%d",&n);
printf("fact == %d\n",fun(n,1));
return 0;
}
int fun(int n, int sofar)
{
int ret = 0;
if(n == 0)
return sofar;
ret = fun(n-1,sofar*n);
return ret;
}
However, even if I do not use return, it still works. This does not make perfect sense since I am returning the value only in the base case. Say if n==5, then 120 would be returned at the base case. But what gets returned from 4th invocation back to the 3rd invocation cannot be predicted since we are not explicitly specifying any return unlike in Code snippet A.
Code snippet B
int fun(int n, int sofar)
{
int ret = 0;
if(n == 0)
return sofar;
ret = fun(n-1,sofar*n);
}
I am thinking the above works because of some kind of compiler optimization ? Because If I add a printf statement to Code snippet B, it does not work anymore.
Code snippet C
int fun(int n, int sofar)
{
int ret = 0;
if(n == 0)
return sofar;
ret = fun(n-1,sofar*n);
printf("now it should not work\n");
}
Probably the printf causes something to be removed from the stack? Please help me understand this.
Not returning a value from a fuction which should return a value is undefined behavior.
If it works by any luck then it's not an optimization but just a coincidence given by how and where these automatic allocated values are stored.
One could speculate about the reason why this works, but there is no way to give a definitive answer: reaching the end of a value-returning function without the return statement and using the return value is undefined behavior, with or without optimization.
The reason this "works" in your compiler is that the return mechanism used by your compiler happens to have the right value at the time the end of function is reached. For example, if your compiler returns integers in the same register that has been used for the last computation in your code (i.e. ret = fun(n-1,sofar*n)) then the right value would be loaded into the return register by accident, masking undefined behavior.
It works because the return value is almost always stored in a specific CPU register (eax for x86). This means that is you don't explicitly return a value, the return register will not be explicitly set. Because of that, its value can be anything, but it is often the return value of the last called function. Thus, ending a function with myfunc() is almost guaranteed to have the same behavior as return myfunc(); (but it's still undefined behavior).
Here is the reason 'something' is calculated.
the call to printf() has a returned value (very rarely used) of the number of characters printed (including tabs, newlines, etc)
in the 'C' code snippet, printf() is returning 23.
'int' returned values are always returned in the same register.
The printf() set that register to 23.
So, something is returned, nothing was removed from the stack.
The reason why it seems to work in B is because the return value is most likely passed in a register on your architecture. So returning through all the layers of recursion (or if the compiler optimized the whole thing into iteration) nothing touches that register and your code appears to work.
A different compiler might not allow this to happen or maybe the next version of your compiler will optimize this differently. In fact, the compiler can remove most of the function because it is allowed to assume that since undefined behavior can't happen it must mean that the part of the function where the undefined behavior seems to happen will never be reached and can be safely removed.

Function with no return statement but compiled and returned right answer

In the section of the code below, there is no return statement in the function but it still compiled and gave the right answer. Is this a normal behavior?
#include <iostream>
int multiply (int x, int y) {
int product = x * y;
}
int main (int argc, char **argv) {
std::cout << multiply(4, 5) << std::endl;
return 0;
}
No, getting the correct answer from the function is not normal behaviour, it's a coincidence. You should not rely on this.
From C++03, 6.6.3 The return statement /2 (and the same section for C++11 as well):
Flowing off the end of a function is equivalent to a return with no value; this results in undefined behavior in a value-returning function.
You'll probably find that you're getting the correct answer simply because of the side effects of your calling convention.
For example, if a function value is returned in the (mtyhical) r0 register, it may be that the calculation uses that register within the function to hold the value, before storing it into the memory representing the product variable. So the fact it's in r0 when you return is just a hang-over from the way things are done.
Compiling with different levels of optimisation, or using another compiler, or even compiling on a Tuesday evening during a blue moon may affect the outcome, that's the main problem with undefined behaviour - it's untrustworthy. At a bare minimum, a good compiler would have warned you about this.

Returning 11 while I am not returning anything

#include<iostream>
using namespace std;
int increment(int i)
{
if(i<=10)
{
cout<<i;
i++;
increment(i);
}
//return 0;
}
int main()
{
cout<<increment(0);
}
It is printing 11 too when I am not returning anything, why do you think it is?
Your increment function is declared as returning int but you're not returning anything. Your compiler should absolutely be generating a warning.
If you're using GCC, you should always specify at least -Wall. I prefer -Wextra, and -Werror will convert these warnings to errors, so the compilation actually fails. See GCC Warning Options.
What's actually happening? The ABI / calling convention for many architectures specify a particular CPU register to hold the return value of a function. (On x86 this is eax, and on ARM this is r0.) Since you have no return statement in your function, the compiler is not going to put any value in that register as the return value before the function returns. Whatever value happened to be in that register is what the calling function will see as the return value.
In the calling conventions for most processors there is a register used to return values that fit in a native register word. The calling conventions also specify which registers are "caller saves" (can be changed without being saved by a function) and "callee saves" (which must either go unused or be saved and restored by a function). The return register is naturally a "caller saves" kind of register because it will be modified by the function to return a value. This means that during the body of a function it is likely to be chosen as a scratch register. In your case, the register gets used for i and since there is no explicit return to modify that register, it is still set to 11 when the function returns to the caller.

How do C++ progs get their return value, when a return is not specified in the function?

I recently wrote a post:
Weird Error in C++ Program: Removing Printout Breaks Program
...in which I was trying to solve a seemingly baffling problem, in which removing a cout statement would break my program.
As it turned out, my problem was that I forgot to return my true/false success flag that I was later using for logic.
But apparently SOMETHING was being returned and that something was always true if I left that cout in, but would seemingly "magically" become false when I took it out.
My question for you all is: What determines what a c++ function return when no return command is executed within the function? Is there any logic to it?
Obviously forgetting your return type is a bad idea. In this case, though, it was largely due to the nature of my program -- a quick hack job. I later decided that it wasn't worth the effort to include implement an algorithm to determine the success/failure of the function call -- but accidentally left behind the code dependent on the return.
Bafflingly g++ gave me no warnings or errors when compiling the executable like so:
g++ main.cc -g -o it_util
My version is:
g++ (GCC) 4.1.2 20080704 (Red Hat 4.1.2-44)
Again, to save others future frustration in case they make the same silly mistake and are met with the same seemingly erratic behavior, can anyone cast light on where a function without a return gets its return value from??
Thanks!!
On x86 calling conventions, the return value for integers and pointers is on the EAX register. The following is an example of that:
int func() {
if(0) return 5; // otherwise error C4716: 'func' : must return a value
}
int main() {
int a;
a = func();
}
Compiling with cl.exe /Zi, MSVC++10:
push ebp
mov ebp, esp
push ecx
call j_?func##YAHXZ ; func(void)
mov [ebp+a], eax ; assumes eax contains the return value
xor eax, eax
mov esp, ebp
pop ebp
retn
Of course, this is all undefined behavior.
There is no logic to it, and most C++ compilers should flag it with a warning. It allowed for backward-compatibility to C.
In K&R C, there was no void type, and when a type was unspecified, it default to int. So,
myfunc() {....}
Was techincally a function returning a int, but most programmers used that form for a routine not returning a value.
The compiler had to make sense of this. So, the convention became, the return would put something into a register. And the assignment in the calling routine would take the value out of the register. Now, if the callee never issued a return, nothing specific would be placed in that register. But it would still have some (random) value in it, which would be blindly assigned in the caller.
From C++ Standard section 6.6.3 The return statement
Flowing off the end of a function is
equivalent to a return with no value;
this results in undefined behavior in
a value-returning function.
There is one exception (as per 3.6.1/5):
If control reaches the end of main without encountering a return
statement, the effect is that of
executing return 0;
The reason this is syntactically allowed is put nicely by James Curran. But with the -Wall gcc option (as commented by Neil) you should be warned on this behavior; something like 'Not all control paths return value in a value-returning function...'.
It depends on the calling convention. For instance, for a 32-bit integer return on an Intel platform, you get whatever is in the eax register.
With a modern compiler you'll probably get an Warning using -Wall
But if you don't return a value, usually you'll get garbage.
"What determines what a c++ function return when no return command is executed within the function? Is there any logic to it?"
The type in the beginning of the function.
Example:
int cow()
{
int temp;
return temp;
}
If you don't return the correct type or return nothing, the compiler should complain. Edit: Oh crap, I've just read your flags. You need to turn on more flags man, -W -Wall -pedantic. Read the g++ manual.
Unless you have a void function. Then you don't have to return anything or you can have pointer to play.
void somefunction( int* ptr_int)
{
int temp = *ptr_int;
temp +=1000;
this->ptr_int = temp;
}
I believe the above code works, it have been awhile since I've coded in C++.