Followers 0

# A strange issue with the scope of the << operator

## 9 posts in this topic

Actually, the title is a bit of a misnomer. I doubt the issue is with the operator itself. More likely it's something [i]I just don't understand[/i]. The problem is, vaguely put:

I'm declaring a variable within [CODE]int main()[/CODE], and then, in one line, altering its value by passing it by reference to a function, then outputting it via [CODE]cout << [/CODE]. Only problem is, [CODE]cout <<[/CODE] is printing the original initialized value of the variable to the screen, rather than the newly altered version. I have come up with a solution, but I don't like it. Actually, the code is simple enough that I can post it (below). It's a simple Half Adder function. Take two binary inputs, output the result and the carry. I pass the carry by reference, and have the function return the result of the addition.

[CODE]
#include <iostream>
using namespace std;

int main(int argc, char ** argv){

bool input[] = {true, true};
bool carry = false;

cout << "Result is " << HalfAdder(input[0], input[1], carry) << " carry is " << carry << endl;
system("PAUSE");

return 0;
}//end of main

bool HalfAdder(bool a, bool b, bool& carry){

if( a & b ){
//1 + 1 = 0, carry = 1
carry = true;
return false;
}//end of if

else{
//1 + 0 = 1, no carry. No carry with 0 + 0 either
carry = false;
//1 + 0 = 1; 0 + 0 = 0
return (a || b) ? true : false;
}//end of else

[/CODE]

If you run this, unfortunately, carry is always 0. False. Because it's initialized as false. This, of course, despite the fact that I pass it by reference in the call. While I'm sure the C/C++ veterans have probably already scrolled down to the reply box by now, for those of you still reading, I'd like to offer a theory for some feedback (I'll do the research later tonight). I believe that the problem is that I'm passing HalfAdder as a parameter to the << member function of cout on the same line that I pass carry to another instance of <<.

So while I expected this sort of thing to happen:

[CODE]

cout.operator<<("Result is");
cout.operator<<("carry is");
cout.operator<<(carry);
[/CODE]

What [i]really[/i] happened is something like...

[CODE]cout.operator<<("Result is", HalfAdder(), "carry is", carry);[/CODE]

Not that [i]exactly[/i], but that basic concept. What I mean is, maybe all of the parameters I passed to << were copied immediately, and [i]then[/i] HalfAdder() was executed, so that even though carry has been altered, it's too late; the original value of carry was copied already. I tested this out by running the same code but adding an extra line before [CODE]system("PAUSE")[/CODE].

[CODE]
cout << "Result is " << HalfAdder(input[0], input[1], carry) << " carry is " << carry << endl;
cout << "But the true carry is " << carry << endl;
system("PAUSE");
[/CODE]

And, hey, it says the true carry is 1, as expected. That's actually pretty amazing. I never even thought of that. Oddly enough, I compiled this in Dev-C++ before handing it in for class, and I assume it worked fine, otherwise I probably wouldn't have handed it in. Is it even remotely possible this is a compiler-specific thing? My most recent build of it where I noticed the error was in MSVC++2012.

Anyway, thanks for your time. Sorry if this was too much too read. I just think it's a pretty cool error to have made.
0

##### Share on other sites
I've faced this problem before.

I believe that this kind of thing with i/o streams
[source]std::cout << a(&val) << val; [/source]
generates an Unspecified Behavior.

The std::cout function will print the arguments in the order you provided, but it cannot guarantee that they will be executed from lef-to-right or right-to-left.
I think that the compiler is the one that is translating this to a [i]random [/i]order of execution. DevC++ (gcc?) did it left-to-right as you expected but the vc++ from Visual Studio did it differently.

Anyhow, I think it is better to break this line into two as you have shown above. Edited by kuramayoko10
0

##### Share on other sites
The problem stems from the order in which arguments are evaluated. It's possible that (a copy of?) carry is evaluated first, before [tt]HalfAdder[/tt] is called. It's also possible that the behavior of the statement is undefined, meaning that you may get different behavior depending on the compiler. For the sake of clarity and readability, I would suggest evaluating [tt]HalfAdder[/tt] separately before writing the result:
[code]
bool result = HalfAdder(input[0], input[1], carry);
cout << "Result is " << result << " carry is " << carry << endl;
[/code]
1

##### Share on other sites
[quote name='fastcall22' timestamp='1349917537' post='4988919']
The problem stems from the order in which arguments are evaluated. It's possible that (a copy of?) carry is evaluated first, before [tt]HalfAdder[/tt] is called. It's also possible that the behavior of the statement is undefined, meaning that you may get different behavior depending on the compiler. For the sake of clarity and readability, I would suggest evaluating [tt]HalfAdder[/tt] separately before writing the result:
[code]
bool result = HalfAdder(input[0], input[1], carry);
cout << "Result is " << result << " carry is " << carry << endl;
[/code]
[/quote]

Actually that was my exact solution. I just thought it'd be more fun to try to find a way to make it work without the extra variable. You and kuramayoko have made me a little more confident that I just expected the wrong kind of behavior and need to learn more about iostream.

Thanks. Any other input?
0

##### Share on other sites
You may want to fix this:
[CODE]if( a & b ){[/CODE]
to:
[CODE]if( a && b ){[/CODE]
Anyway the result you are getting is not strange at all, since your parameters are being pushed right-to-left. [i]carry[/i] was already on the stack to be printed before it ever got passed to HalfAdder().

fastcall22’s suggestion will net you the proper result.

L. Spiro Edited by L. Spiro
1

##### Share on other sites
[quote name='L. Spiro' timestamp='1349917779' post='4988922']
You may want to fix this:
[CODE]if( a & b ){[/CODE]
to:
[CODE]if( a && b ){[/CODE]
Anyway the result you are getting is not strange at all, since parameters are pushed right-to-left. [i]carry[/i] was already on the stack to be printed before it ever got passed to HalfAdder().

fastcall22’s suggestion will net you the proper result.

L. Spiro
[/quote]

I did not know that. I'm glad I made this mistake on a small assignment, and not something complex that would've driven me crazy. Thanks a lot guys.
0

##### Share on other sites
If in doubt, [b]never[/b] rely on expressions to be evaluated in any particular order (this behavior can change even between debug and release builds).

Notable exceptions: logical operators (&&, ||) and the comma operator (the operator, [b]not[/b] just any comma like in parameter lists)
1

##### Share on other sites
What Trienco is saying is that you should get familiar with the notion of "[url="http://en.wikipedia.org/wiki/Sequence_point"]sequence point[/url]".

If you don't want the extra variable, break up the cout << ...'statement into two. As long as there is a ;' in between the printing of the two values, you'll be fine (because ;' introduces a sequence point).
2

##### Share on other sites
[quote name='alvaro' timestamp='1349940968' post='4989005']
What Trienco is saying is that you should get familiar with the notion of "[url="http://en.wikipedia.org/wiki/Sequence_point"]sequence point[/url]".

If you don't want the extra variable, break up the cout << ...'statement into two. As long as there is a ;' in between the printing of the two values, you'll be fine (because ;' introduces a sequence point).
[/quote]

0

##### Share on other sites
[quote name='L. Spiro' timestamp='1349917779' post='4988922']
Anyway the result you are getting is not strange at all, since parameters are pushed right-to-left....
[/quote]
Or left-to-right. Or as a thunk. Or passed in registers. Or the function is inlined and aliases are hoisted.
1

## Create an account

Register a new account