c++ return value - c++

I have the following code in c++:
int fff ( int a , int b )
{
if (a>b )
return 0;
else a+b ;
}
although I didn't write 'return' after else it does not make error ! < br/>
in main() when I wrote:
cout<<fff(1,2);
it printed 1 ?
How did that happened
can any one Explain that ?

This what is called undefined behavior. Anything can happen.
C++ does not require you to always return a value at the end of a function, because it's possible to write code that never gets there:
int fff ( int a , int b )
{
if (a>b )
return 0;
else return a+b;
// still no return at end of function
// syntactically, just as bad as original example
// semantically, nothing bad can happen
}
However, the compiler cannot determine if you never get to the end of the function, and the most it can do is give a warning. It's up to you to avoid falling off the end without a return.
And if you do, you might get a random value, or you might crash.

$6.6.3/2- "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."
A compiler may or may not diagnose such a condition.
Here
else a + b;
is treated as an expression without any side effect.

the "random" return vaule is determined by the CPU register value after the call, since the register is 1 after the call, so the value is 1.
If you change you code, the function will return diffrent value.

A good compiler (e.g. gcc) will issue a warning if you make such a mistake, and have a command line switch to return a non-zero error status if any warnings were encountered. This is undefined behaviour: the result you're seeing is whatever value happened to be in the place that the compiler would normally expect a function returning int to use: for example, the accumulator register or some spot on the stack. Your code doesn't copy a+b into that location, so whatever was last put in there will be seen instead. Still, you're not even guaranteed to get a result - some compiler/architecture might do something that can crash the machine if the function didn't have a return statement: for example - pop() a value from the stack on the assumption that return has pushed one - future uses of the stack (including reading function-return addresses) could then get results from the memory address above or below the intended one.

Related

c++ code behaves abnormally when the return value is missing

GCC 9.2.1 gives a warning that there is "no return statement in function returning non-void", however, the code does compile (I compiled with flags -O3 and -finline-functions).
I expected the program to have no output, as the condition for the while loop should evaluate to false. However, I got the following output from the program (printed in the while loop):
"it != mMap.end(): 0"
The output is particularly odd, given that the printed value (i.e., 0 or "false") is also the condition for the while loop.
After the print, the program segfaults because the iterator becomes invalid (via it++ in the while loop that should never have executed).
I guess this can all be chalked up to the missing return value. But, I find it surprising that the code behaves so pathologically simply because a return value isn't supplied. I'd appreciate any insight into understanding what's happening at a deeper level.
#include <iostream>
#include <tr1/unordered_map>
struct Test
{
int Dummy (void) const
{
std::tr1::unordered_map<int, int>::const_iterator it = mMap.begin();
while (it != mMap.end())
{
std::cout << "it != mMap.end(): " << (it != mMap.end()) << std::endl;
it++;
}
}
std::tr1::unordered_map<int, int> mMap;
};
int main (void)
{
Test test;
test.Dummy();
return 0;
}
Returning from a non-void function without supplying a return value is underfined behavior, and therefore the compiler can do whatever it wants.
What the compiler has done in this case in particular, seems to be that it has spotted that skipping the loop would trigger UB and therefore assumes the loop is entered at least once. Therefore it assumes that it can safely enter the loop without checking the condition as the compiler trusts that the author of the program did not invoke any undefined behavior.
This is of course speculation from my part.
You should turn on warnings using -Wextra and -Wall in gcc which will e.g. enable the warning Control reaches the end of a non-void function so you will hopefully not forget about fixing stuff like that. To enforce it, enable the compiler flag -Werror.
Not returning a value invokes undefined behavior so the compiler is allowed to either return a garbage value or crash your program (this is what clang typically does) if the function returns. This is bad and you should never keep broken code like that. For additional insight you can use a disassembler and see what your compiler did at the end of the function.

Weird behaviour in for-loop in C++ on Mac

I have the following function:
std::vector<std::vector<Surfel>> testAddingSift(
const Groundtruth &groundtruth,
SurfelHelper &surfelHelper) {
for (int k = 0; k < 10; k++) {
std::cout << "hej" << k <<std::endl;
}
}
When I forgot to return a vector<vector<Surfel>> I got an infinite loop:
hej1025849
hej1025850
hej1025851
hej1025852
When I return a vector<vector<Surfel>> I get:
hej0
hej1
hej2
hej3
hej4
hej5
hej6
hej7
hej8
hej9
Of course it was a mistake to forget to return the vector, but why is the for-loop affected?
I am using a MacBook Pro with Sierra and CLion and I think it is clang.
Failure to return from a function with non-void return type is undefined behavior. Doing so makes it, by definition, nearly impossible to reason about the resulting behavior. This can affect the behavior of code that comes before the point where undefined behavior would be expected to be encountered.
The proper answer here is that this is, of course, undefined behavior, so anything could happen. A more interesting question is, how in the world would something silly, like forgetting a return statement, lead to an infinite loop?
It is not the first time I forget to return something, but that has never caused this kind of problems before.
My best guess is that the result that you see has to do with returning an object by value when the object has a non-trivial copy constructor. In your case, copy constructor is rather non-trivial, because it needs to deal with nested arrays. In particular, I suspect that the infinite loop would go away if you change return type to an int (the behavior would remain undefined, though).
My guess is that when your loop calls operator << it places return address on the stack. Once operator << returns, the stack frame becomes unused, but its content remains intact. I suspect that the code for copying the returned vector re-interprets the content of the "garbage" stack frame as a vector with lots of elements, and invokes loop's body instead of copying array elements.
This is just one possibility. If you would like to find out what is happening, the proper way would be to dig through the disassembly.

Don't we have to assign return values of the functions to variables? C/C++

I've been using C/C++ for about three years and I can't believe I've never encountered this issue before!
This following code compiles (I've just tried using gcc):
#include <iostream>
int change_i(int i) {
int j = 8;
return j;
}
int main() {
int i = 10;
change_i(10);
std::cout << "i = " << i << std::endl;
}
And, the program prints i = 10, as you might expect.
My question is -- why does this compile? I would have expected an error, or at least a warning, saying there was a value returned which is unused.
Naively, I would consider this a similar case to when you accidentally forget the return call in a non-void function. I understand it's different and I can see why there's nothing inherently wrong with this code, but it seems dangerous. I've just spotted a similar error in some very old code of mine, representing a bug which goes back a long time. I obviously meant to do:
i = change_i(10);
But forgot, so it was never changed (I know this example is silly, the exact code is much more complicated). Any thoughts would be much appreciated!
It compiles because calling a function and ignoring the return result is very common. In fact, the last line of main does so too.
std::cout << "i = " << i << std::endl;
is actually short for:
(std::cout).operator<<("i =").operator<<(i).operator<<(std::endl);
... and you are not using the value returned from the final operator<<.
Some static checkers have options to warn when function returns are ignored (and then options to annotate a function whose returns are often ignored). Gcc has an option to mark a function as requiring the return value be used (__attribute__((warn_unused_result))) - but it only works if the return type doesn't have a destructor :-(.
Ignoring the return value of a function is perfectly valid. Take this for example:
printf("hello\n");
We're ignoring the return value of printf here, which returns the number of characters printed. In most cases, you don't care how many characters are printed. If compilers warned about this, everyone's code would show tons of warnings.
This actually a specific case of ignoring the value of an expression, where in this case the value of the expression is the return value of a function.
Similarly, if you do this:
i++;
You have an expression whose value is discarded (i.e. the value of i before being incremented), however the ++ operator still increments the variable.
An assignment is also an expression:
i = j = k;
Here, you have two assignment expressions. One is j = k, whose value is the value of k (which was just assigned to j). This value is then used as the right hand side an another assignment to i. The value of the i = (j = k) expression is then discarded.
This is very different from not returning a value from a non-void function. In that case, the value returned by the function is undefined, and attempting to use that value results in undefined behavior.
There is nothing undefined about ignoring the value of an expression.
The short reason it is allowed is because that's what the standard specifies.
The statement
change_i(10);
discards the value returned by change_i().
The longer reason is that most expressions both have an effect and produce a result. So
i = change_i(10);
will set i to be 8, but the assignment expression itself also has a result of 8. This is why (if j is of type int)
j = i = change_i(10);
will cause both j and i to have the value of 8. This sort of logic can continue indefinitely - which is why expressions can be chained, such as k = i = j = 10. So - from a language perspective - it does not make sense to require that a value returned by a function is assigned to a variable.
If you want to explicitly discard the result of a function call, it is possible to do
(void)change_i(10);
and a statement like
j = (void)change_i(10);
will not compile, typically due to a mismatch of types (an int cannot be assigned the value of something of type void).
All that said, several compilers (and static code analysers) can actually be configured to give a warning if the caller does not use a value returned by a function. Such warnings are turned off by default - so it is necessary to compile with appropriate settings (e.g. command line options).
I've been using C/C++ for about three years
I can suppose that during these three years you used standard C function printf. For example
#include <stdio.h>
int main( void )
{
printf( "Hello World!\n" );
}
The function has return type that differs from void. However I am sure that in most cases you did not use the return value of the function.:)
If to require that the compiler would issue an error when the return value of a function is not used then the code similar to the shown above would not compile because the compiler does not have an access to the source code of the function and can not determine whether the function has a side effect.:)
Consider another standard C functions - string functions.
For example function strcpy is declared like
char * strcpy( char *destination, const char *source );
If you have for example the following character arrays
char source[] = "Hello World!";
char destination[sizeof( source )];
then the function usually is called like
strcpy( destination, source );
There is no sense to use its return value when you need just to copy a string. Moreover for the shown example you even may not write
destination = strcpy( destination, source );
The compiler will issue an error.
So as you can see there is sense to ignore sometimes return values of functions.
For your own example the compiler could issue a message that the function does not have a side effect so its call is obsolete. In any case it should issue a message that the function parameter is not used.:)
Take into account that sometimes the compiler does not see a function definition that is present in some other compilation unit or in a library. So the compiler is unable to determine whether a function has a side effect,
In most cases compilers deal with function declarations. Sometimes the function definitions are not available for compilers in C and C++.

Conflicting outputs when value referenced by a pointer no longer exists

#include<iostream.h>
#include<conio.h>
int *p;
void Set()
{
int i;
i=7;
p=&i;
}
int Use()
{
double d;
d=3.0;
d+=*p;
//if i replace the above 3 statements with --> double d=3.0+*p; then output is 10 otherwise the output is some random value(address of random memory location)
//why is this happening? Isn't it the same?
return d;
}
void main()
{
clrscr();
Set();
cout<<Use();
getch();
}
My question is as mentioned in comments above.I want to know the exact reason for the difference in outputs.In the above code output is some address of random memory location and i understand that is because of i is a local variable of Set() but then how is it visible in the second case that is by replacing it with double d=3.0+*p; because then the output comes 10( 7+3 ) although 7 should not have been visible?
The result of using pointer p is undefined, it could also give you a segfault or just return 42. The technical reason behind the results your'e getting are probably:
i inside Set is placed on the stack. The value 7 ist stored there and p points to that location in memory. When you return from Set value remains in memory: the stack is not "destroyed", it's just the stack pointer which is reset. p still points to this location which still contains the integer representation of "3".
Inside Use the same location on the stack is reused for d.
When the compiler is not optimizing, in the first case (i.e. the whole computation in one line), it first uses the value 7 (which is still there in memory with p pointing to it), does the computation, overwrites the value (since you assign it to d which is at the same location) and returns it.
In the second case, it first overwrites the value withe the double value 3.0 and then takes the first 4 bytes interpreted as integer value for evaluating *p in d+=*p.
This case shows why returning pointers/references to local variables is such a bad thing: when writing the function Set you could even write some kind of unit tests and they would not detect the error. It might get unnoticed just until the software goes into production and has to perform some really critical task and just fails then.
This applies to all kindes of "undefined behaviour", especially in "low level" languages like C/C++. The bad thing is that "undefined" may very well mean "perfectly working until it's too late"...
After exiting function Set the value of pointer p becomes invalid due to destroying local variable i. The program has undefined behavior.

enum has unexpected value on Windows but not Linux

I cant get enum this to work properly on Windows. While compiling on linux it returns expected value, but on windows it returns some random number.
typedef enum wezly {
elektrownie1,
konwencjonalne1,
niekonwencjonalne1,
weglowa1,
jadrowa1,
sloneczna1,
wiatrowa1,
geotermiczna1,
gazowa1,
wodna1,
maremotoryczna1,
maretermiczna1
};
wezly wybor_wezla(string opcja)
{
string bb;
bb = opcja;
if ((bb.compare("[elektrownie]")==0)||(bb.compare("[ELEKTROWNIE]")==0))
return elektrownie1;
else if ((bb.compare("[konwencjonalne]")==0)||(bb.compare("[KONWENCJONALNE]")==0))
return konwencjonalne1;
else if ((bb.compare("[gazowa]")==0)||(bb.compare("[GAZOWA]")==0))
return gazowa1;
else if ((bb.compare("[wodna]")==0)||(bb.compare("[WODNA]")==0))
return wodna1;
// (and so on...)
}
int main()
{
cout << wybor_wezla("[gazowa]");
}
When on linux i get 7, on windows its some random number....
Why can that be ?
It's actually broken here (after looking at the link you gave in the comments):
bb=opcja.substr((opcja.find_first_of("[")),(opcja.find_first_of("]"))-1);
This results in extracting a string like "[whateve" if the input is "... [whatever] ...".
What I think you mean is:
bb=opcja.substr((opcja.find_first_of("[")),(opcja.find_first_of("]"))-opcja.find_first_of("[")+1);
Which results in extracting a string like "[whatever]" from the input.
The original code, given the input "[gazowa]", will compare "[gazow" to various strings, none will match, and the end of the function will be reached without hitting a return statement.
This results in undefined behaviour. Hence your result of 7 on linux, and some other value on windows, when [gazowa] ought to give you 8.
You also need to do something more sensible to handle the case where none of your strings are matched, i.e. if the end of wybor_wezla is reached. What you do in that case is up to you, but as a start I'd at least put a print statement in there so you know when nothing's matched.
Your code is missing a final else clause:
wezly wybor_wezla(string opcja)
{
if(...)
return ...;
else if(...)
return ...;
else if(...)
return ...;
// No final else!
}
When none of the if clauses are true, it falls off the end of the function without returning a value, which is Undefined Behavior. In this case, it's returning a garbage value, but worse stuff could happen.
Your first action should be to add a final else clause. This can return a default value, an error code, throw an exception, abort(), etc., but it cannot do nothing. If you know the value has to be one of a limited set of things, you could change the final else if into just an else and assume that if it's not the first N-1 things, it's the Nth thing.
Once you've done that, you need to figure out why your data isn't falling into one of the expected cases and fix that.