Confused about the function return value - c++

#include<iostream>
using namespace std;
int Fun(int x)
{
int sum=1;
if(x>1)
sum=x*Fun(x-1);
else
return sum;
}
int main()
{
cout<<Fun(1)<<endl;
cout<<Fun(2)<<endl;
cout<<Fun(3)<<endl;
cout<<Fun(4)<<endl;
cout<<Fun(5)<<endl;
}
This function is to compute the factorial of an integer number. In the branch of x>1,there is no return value for function Fun. So this function should not return correct answer.
But when fun(4) or some other examples are tested, the right answers are got unexpectedly. Why?
The assembly code of this function is(call Fun(4)):
0x004017E5 push %ebp
0x004017E6 mov %esp,%ebp
0x004017E8 sub $0x28,%esp
0x004017EB movl $0x1,-0xc(%ebp)
0x004017F2 cmpl $0x1,0x8(%ebp)
0x004017F6 jle 0x40180d <Fun(int)+40>
0x004017F8 mov 0x8(%ebp),%eax
0x004017FB dec %eax
0x004017FC mov %eax,(%esp)
0x004017FF call 0x4017e5 <Fun(int)>
0x00401804 imul 0x8(%ebp),%eax
0x00401808 mov %eax,-0xc(%ebp)
0x0040180B jmp 0x401810 <Fun(int)+43>
0x0040180D mov -0xc(%ebp),%eax
0x00401810 leave
0x00401811 ret
May be this is the reason: The value of sum is saved in register eax, and the return value is saved in eax too, so Funreturn the correct result.

Usually, EAX register is used to store return value, ad it is also used to do other stuff as well.
So whatever has been loaded to that register just before the function returns will be the return value, even if you don't intend to do so.
You can use the -S option to generate assembly code and see what happened to EAX right before the "ret" instruction.

When your program pass in the if condition, no return statement finish the function. The number you got is the result of an undefined behavior.
int Fun(int x)
{
int sum=1.0;
if(x>1)
sum=x*Fun(x-1);
else
return sum;
return x; // return something here
}

Just remove else from your code:
int Fun(int x)
{
int sum=1;
if(x>1)
sum=x*Fun(x-1);
return sum;
}

The code you have has a couple of errors:
you have an int being assigned the value 1.0 (which will be implicitly cast/converted), not an error as such but inelegant.
you have a return statement inside a conditionality, so you will only ever get a return when that if is true
If you fix issue with the return by removing the else, then all will be fine:)
As to why it works with 4 as an input, that is down to random chance/ some property of your environment as the code you have posted should be unable to function, as there will always be an instance, when calculating factorials for a positive int, where x = 1 and no return will be generated.
As an aside, here is a more concise/terse function: for so straightforward a function you might consider the ternary operator and use a function like:
int factorial(int x){ return (x>1) ? (x * factorial(x-1)) : 1;}
this is the function I use for my factorials and have had on library for the last 30 or so years (since my C days) :)

From the C standards:
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.
Your situation is the same as this one:
int fun1(int x)
{
int sum = 1;
if(x > 1)
sum++;
else
return sum;
}
int main()
{
int b = fun1(3);
printf("%d\n", b);
return 0;
}
It prints 2 on my machine.
This is calling convention and architecture dependent. The return value is the result of last expression evaluation, stored in the eax register.

As stated in the comment this is undefined behaviour. With g++ I get the following warning.
warning: control reaches end of non-void function [-Wreturn-type]
On Visual C++, the warning is promoted to an error by default
error C4716: 'Fun' : must return a value
When I disabled the warning and ran the resulting executable, Fun(4) gave me 1861810763.
So why might it work under g++? During compilation conditional statements are turned into tests and jumps (or gotos). The function has to return something, and the simplest possible code for the compiler to produce is along the following lines.
int Fun(int x)
{
int sum=1.0;
if(!(x>1))
goto RETURN;
sum=x*Fun(x-1);
RETURN:
return sum;
}
This is consistent with your disassembly.
Of course you can't rely on undefined behaviour, as illustrated by the behaviour in Visual C++. Many shops have a policy to treat warnings as errors for this reason (also as suggested in a comment).

Related

Curious missed optimization of recursive constexpr function by Clang

Today I wanted to test, how Clang would transform a recursive power of two function and noticed that even with known exponent, the recursion is not optimized away even when using constexpr.
#include <array>
constexpr unsigned int pow2_recursive(unsigned int exp) {
if(exp == 0) return 1;
return 2 * pow2_recursive(exp-1);
}
unsigned int pow2_5() {
return pow2_recursive(5);
}
pow2_5 is compiled as a call to pow2_recursive.
pow2_5(): # #pow2_5()
mov edi, 5
jmp pow2_recursive(unsigned int) # TAILCALL
However, when I use the result in a context that requires it to be known at compile time, it will correctly compute the result at compile time.
unsigned int pow2_5_arr() {
std::array<int, pow2_recursive(5)> a;
return a.size();
}
is compiled to
pow2_5_arr(): # #pow2_5_arr()
mov eax, 32
ret
Here is the link to the full example in Godbolt: https://godbolt.org/z/fcKef1
So, am I missing something here? Is there something that can change the result at runtime and a reason, that pow2_5 cannot be optimized in the same way as pow2_5_arr?

What happens when there's an error in constexpr function?

I learnt that constexpr functions are evaluated at compile time. But look at this example:
constexpr int fac(int n)
{
return (n>1) ? n*fac(n-1) : 1;
}
int main()
{
const int a = 500000;
cout << fac(a);
return 0;
}
Apparently this code would throw an error, but since constexpr functions are evaluated at compiling time, why I see no error when compile and link?
Further on, I disassembled this code, and it turned out this function isn't evaluated but rather called as a normal function:
(gdb) x/10i $pc
=> 0x80007ca <main()>: sub $0x8,%rsp
0x80007ce <main()+4>: mov $0x7a11f,%edi
0x80007d3 <main()+9>: callq 0x8000823 <fac(int)>
0x80007d8 <main()+14>: imul $0x7a120,%eax,%esi
0x80007de <main()+20>: lea 0x20083b(%rip),%rdi # 0x8201020 <_ZSt4cout##GLIBCXX_3.4>
0x80007e5 <main()+27>: callq 0x80006a0 <_ZNSolsEi#plt>
0x80007ea <main()+32>: mov $0x0,%eax
0x80007ef <main()+37>: add $0x8,%rsp
0x80007f3 <main()+41>: retq
However, if I call like fac(5):
constexpr int fac(int n)
{
return (n>1) ? n*fac(n-1) : 1;
}
int main()
{
const int a = 5;
cout << fac(a);
return 0;
}
The assemble code turned into:
(gdb) x/10i $pc
=> 0x80007ca <main()>: sub $0x8,%rsp
0x80007ce <main()+4>: mov $0x78,%esi
0x80007d3 <main()+9>: lea 0x200846(%rip),%rdi # 0x8201020 <_ZSt4cout##GLIBCXX_3.4>
0x80007da <main()+16>: callq 0x80006a0 <_ZNSolsEi#plt>
0x80007df <main()+21>: mov $0x0,%eax
0x80007e4 <main()+26>: add $0x8,%rsp
0x80007e8 <main()+30>: retq
The fac function is evaluated at compile time.
Can Anyone explain this?
Compiling command:
g++ -Wall test.cpp -g -O1 -o test
And with g++ version 7.4.0, gdb version 8.1.0
I learnt that constexpr functions are evaluated at compile time
No, constexpr can be evaluated at compile time, but also at runtime.
further reading:
Difference between `constexpr` and `const`
https://en.cppreference.com/w/cpp/language/constexpr
Purpose of constexpr
Apparently this code would throw an error
No, no errors thrown. For large input, the result will overflow which is undefined behavior. This doesn't mean an error will be thrown or displayed. It means anything can happen. And when I say anything, I do mean anything. The program can crash, hang, appear to work with a strange results, display weird characters, or literally anything.
further reading:
https://en.cppreference.com/w/cpp/language/ub
https://en.wikipedia.org/wiki/Undefined_behavior
http://blog.llvm.org/2011/05/what-every-c-programmer-should-know.html
And, as pointed out by nathanoliver
when invoked in a constant expression, a constexpr function must check and error out on UB http://coliru.stacked-crooked.com/a/43ccf2039dc511d5
In other words there can't be any UB at compile time. What at runtime would be UB, at compile time it's a hard error.
constexpr it means that it can be evaluated at compile time, not that it will be evaluated at compile time. The compiler will be forced to do the evaluation compile-time if you use it where a compile time constant is expected (e.g. the size of an array).
On the other hand for small values g++ is for example smart enough to compute the result compile time (even without constexpr).
For example with:
int fact(int n) {
return n < 2 ? 1 : n*fact(n-1);
}
int bar() {
return fact(5);
}
the code generated by g++ -O3 for bar is:
bar():
mov eax, 120
ret
Note that overflowing the call stack (e.g. infinite or excessive recursion) or even overflowing signed integer arithmetic is in C++ undefined behavior and anything can happen. It doesn't mean you'll get a nice "error" or even a segfault... but that ANYTHING can happen (including, unfortunately, nothing evident). Basically it means that the authors of compilers can just ignore to handle those cases because you're not supposed to do this kind of mistakes.

why is the optimizer not allowed to fold in "constant context"?

__builtin_is_constant_evaluated is the builtin used to for implementing std::is_constant_evaluated in the standard library on clang and gcc.
code that is not valid in constant context is also often harder for the optimizer to constant fold.
for example:
int f(int i) {
if (__builtin_is_constant_evaluated())
return 1;
else {
int* ptr = new int(1);
int i = *ptr;
delete ptr;
return i;
}
}
is emitted by gcc -O3 as:
f(int):
sub rsp, 8
mov edi, 4
call operator new(unsigned long)
mov esi, 4
mov rdi, rax
call operator delete(void*, unsigned long)
mov eax, 1
add rsp, 8
ret
so the optimizer used __builtin_is_constant_evaluated() == 0
clang fold this to a constant but this is because clang's optimizer can remove unneeded dynamic allocation, not because it used __builtin_is_constant_evaluated() == 1.
i am aware that this would make the return value of __builtin_is_constant_evaluated() implementation defined because optimization vary from one compiler to an other. but is_constant_evaluated should already be used only when both path have the same observable behaviors.
why does the optimizer not use __builtin_is_constant_evaluated() == 1 and fallback to __builtin_is_constant_evaluated() == 0 if it wasn't able to fold ?
Per [meta.const.eval]:
constexpr bool is_constant_evaluated() noexcept;
Returns: true if and only if evaluation of the call occurs within the evaluation of an expression or conversion that is manifestly
constant-evaluated ([expr.const]).
f can never be invoked in a constant-evaluated expression or conversion, so std::is_constant_evaluated() returns false. This is decided by the compiler and has nothing to do with the optimizer.
Of course, if the optimizer can prove that the branches are equivalent, it can do constant fold. But that is optimization after all — beyond the scope of the C++ language itself.
But why is it this way? The proposal that introduced std::is_constant_evaluated is P0595. It explains the idea well:
constexpr double power(double b, int x) {
if (std::is_constant_evaluated() && x >= 0) {
// A constant-evaluation context: Use a
// constexpr-friendly algorithm.
double r = 1.0, p = b;
unsigned u = (unsigned)x;
while (u != 0) {
if (u & 1) r *= p;
u /= 2;
p *= p;
}
return r;
} else {
// Let the code generator figure it out.
return std::pow(b, (double)x);
}
}
// ...
double thousand() {
return power(10.0, 3); // (3)
}
[...]
Call (3) is a core constant expression, but an implementation is not
required to evaluate it at compile time. We therefore specify that it
causes std::is_constant_evaluated() to produce false. It's
tempting to leave it unspecified whether true or false is produced
in that case, but that raises significant semantic concerns: The
answer could then become inconsistent across various stages of the
compilation. For example:
int *p, *invalid;
constexpr bool is_valid() {
return std::is_constant_evaluated() ? true : p != invalid;
}
constexpr int get() { return is_valid() ? *p : abort(); }
This example tries to count on the fact that constexpr evaluation
detects undefined behavior to avoid the non-constexpr-friendly call to
abort() at compile time. However, if std::is_constant_evaluated()
can return true, we now end up with a situation where an important
run-time check is by-passed.

Do compilers reduce simple functions given constant arguments into unique instructions?

This is something I've always thought to be true but have never had any validation. Consider a very simple function:
int subtractFive(int num) {
return num -5;
}
If a call to this function uses a compile time constant such as
getElement(5);
A compiler with optimizations turned on will very likely inline this. What is unclear to me however, is if the num - 5 will be evaluated at runtime or compile time. Will expression simplification extend recursively through inlined functions in this manner? Or does it not transcend functions?
We can simply look at the generated assembly to find out. This code:
int subtractFive(int num) {
return num -5;
}
int main(int argc, char *argv[]) {
return subtractFive(argc);
}
compiled with g++ -O2 yields
leal -5(%rdi), %eax
ret
So the function call was indeed reduced to a single instruction. This optimization technique is known as inlining.
One can of course use the same technique to see how far a compiler will go with that, e.g. the slightly more complicated
int subtractFive(int num) {
return num -5;
}
int foo(int i) {
return subtractFive(i) * 5;
}
int main(int argc, char *argv[]) {
return foo(argc);
}
still gets compiled to
leal -25(%rdi,%rdi,4), %eax
ret
so here both functions where just eliminated at compile time. If the input to foo is known at compile time, the function call will (in this case) simply be replaced by the resulting constant at compile time (Live).
The compiler can also combine this inlining with constant folding, to replace the function call with its fully evaluated result if all arguments are compile time constants. For example,
int subtractFive(int num) {
return num -5;
}
int foo(int i) {
return subtractFive(i) * 5;
}
int main() {
return foo(7);
}
compiles to
mov eax, 10
ret
which is equivalent to
int main () {
return 10;
}
A compiler will always do this where it thinks it is a good idea, and it is (usually) way better in optimizing code on this low level than you are.
It's easy to do a little test; consider the following
int foo(int);
int bar(int x) { return x-5; }
int baz() { return foo(bar(5)); }
Compiling with g++ -O3 the asm output for function baz is
xorl %edi, %edi
jmp _Z3fooi
This code loads a 0 in the first parameter and then jumps into the code of foo. So the code from bar is completely disappeared and the computation of the value to pass to foo has been done at compile time.
In addition returning the value of calling the function became just a jump to the function code (this is called "tail call optimization").
A smart compiler will evaluate this at compile time and will replace the getElement(5) because it will never have a different result. None of the variables are considered volatile.

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++.