beginner C++ question (int increment)

i can't see a better forum then this,

I have just started learning C++ my first real language ( i know perl pretty well)

was just trying stuff, getting farmilar with the way things can be expressed.

came across this.


Code:
int main()


{
void increment();	

}


void increment()
{
	using namespace std;
	int y = 5,x;
	x = (++y)+ (++y) + (++y);
	cout<<x<<endl;
}

now this equals 24, by my logic and order of operations this should be 21 ( 6 + 7+ 8) but its doing 8+8+8. i can speculate why its doing it and how, but can someone explain exactly why?


cheers
 
funny how just after a post it clicks in your head :D

value++ has higher precedence then + , so all value++ are evaluated first then addition is performed......
 
I think the problem is not with precedence because you already use parenthesis.
In C++, the execution order of statements with side-effect is generally not guaranteed. A more detailed explanation can be found in the C++ standard about sequence point and undefined behavior.

Basically, your (++y) + (++y) + (++y) is undefined behavior, and can produce different results from different compilers (or even from different optimization levels).
 
++value or value++? (HINT: try each)

yep that was a typo but its the same either way because the both have higher precedence then addition

I think the problem is not with precedence because you already use parenthesis.
In C++, the execution order of statements with side-effect is generally not guaranteed. A more detailed explanation can be found in the C++ standard about sequence point and undefined behavior.

i googled c++ side effect and found in the first link
http://www.learncpp.com/cpp-tutorial/33-incrementdecrement-operators-and-side-effects/
Side effects can also be dangerous:
1
2

int x = 5;
int nValue = Add(x, ++x);

C++ does not define the order in which function parameters are evaluated. If the left parameter is evaluated first, this becomes a call to Add(5, 6), which equals 11. If the right parameter is evaluated first, this becomes a call to Add(6, 6), which equals 12!

As a general rule, it is a good idea to avoid the use operators that cause side effects inside of compound expressions. This includes all assignment operators, plus the increment and decrement operators. Any operator that causes a side effect should be placed in it’s own statement.

Note that side effects are not confined to operators, expressions, and statements. Functions can also have side effects, which we will discuss in the section on global variables (and why they are evil).
 
lol... error in code let me fix that :)


copy and paste + bad edit. I get 15.
which is more confusing in a way


Code:
int main()
{
increment();	



}


void increment()
{
	
	using namespace std;
	int y = 5,x;
	x = (++y)+ (++y) + (++y);
	cout << " y equals :  " << y << endl;
	cout << " x equals :  " << x << endl;
	


	int a = 5,b;
	b = (a++)+ (a++) + (a++);
	cout << " a equals :  " << a << endl;
	cout << " b equals :  " << b << endl;

}

result:

Code:
 y equals :  8
 x equals :  24
 a equals :  8
 b equals :  15
Press any key to continue . . .
 
Last edited by a moderator:
I
Basically, your (++y) + (++y) + (++y) is undefined behavior, and can produce different results from different compilers (or even from different optimization levels).
Seconded! Don't do it.
 
So why do you think it does this? :)

because its evil :cool:

i can see what its done ( pretty simple really )
why it does it i dont know because as far as i know value++ has higher precedence then + so they should be done first ( very well could be and just not being added to "a" until after the additions have been evaluated).


when i do
Code:
	int c = 5,d;
	d = (c++);
	cout << " c equals :  " << c << endl;
	cout << " d equals :  " << d << endl;

i see the same behavior , so im guessing that the evaluate then add isn't just for the assigned variable but for the whole compound expression.

Code:
	int c = 5,d;
	d = (c++) * 3;
	cout << " c equals :  " << c << endl;
	cout << " d equals :  " << d << endl;

Code:
c equals :  6
 d equals :  15
Press any key to continue . . .

the above would seem to confirm that.
 
Order of precedence is not the same as order of execution. Precedence removes ambiguity about which part of the expression an operator applies to, but doesn't dictate when the operation is carried out.
 
"<type> ordering" means that the order of evaluation is dictated by the language specification, "strong ordering" means that even if something could be re-arranged behind the curtain, it's not re-arranged ever. "weak ordering" means that it's only necessary that the visible effects need to appear as-if ordered respective some context (=> a specific observer situation, not all and any), but operations can and will be re-arranged, and other contexts may observe no apparent ordering at all.
But that distinction only becomes important for you if you look at memory-models and multi-processing.

If you compile a debug-build the compiler often makes everything strong ordered, because it's easier and otherwise the compiler would have to re-order your source-code as well, according to what's going on on the CPU. If you try to debug a release-build, you observe that the debugger is mostly unable to provide you with a correct state-view (what's in what variables etc.) because it's all re-arranged behind the curtain.

But back to your example. I'm sure VC does apply a coherent interpretation of the meaning of the used operators (nothing to do with precedence). That is, the prefix operator has the highest priority and post-evaluation visibility, it will execute all prefix-operations in the line first. The postfix operator has the lowest priority and pre-evaluation visibility, and it will execute all postfix-operations in the line last. For the compiler the line(s) translate(s) to:

y = y + 1, y = y + 1, y = y + 1, x = y + y + y; /* prefix */ or
x = y + y + y, y = y + 1, y = y + 1, y = y + 1; /* postfix */

That is, prefix/postfix-ops are taken out of the statement and put before and after the original statement. Which has something to do with the definition regarding visibility, prefix-op changes become visible before the variable is queried for it's value, postfix-op changes become visible after the variable is queried. In your case the compiler translates this to: prefix-op changes become visible before the statement is executed, and the variable is queried for it's value, and: postfix-op changes become visible after the statement is executed, and the variable is queried for it's value.

As others said, if you can't understand how a statement operates, don't use it. If you need an hour thinking of how it may operate, and you have doubts it may work always the same, don't use it. C/C++ is not a challenge for spagetti-code or for testing your cognitive abilities to understand spagetti-code.

For that, I suggest you this: :devilish:
Code:
#include<stdlib.h>
#include<stdio.h>
#define F for(
#define D return
#define E typedef
#define V malloc(sizeof
#define Z(x)(t(0,(x-C)/y)-l+1e-6*(x-Q))
#define i m(p(r,o,v),e,d 
E double P;E long N;E char*w;N G,l,I,C,B,A,W,L,S,R,O,c,k,s=80,U=13,T=169;P
sqrt(P);N H(){F;O=scanf(" %1[#]%*[^\n]",&O););scanf("%ld%*c",&O);D O;}P
M(N R){s=s>=k?printf("%ld%c"+3*(C<1),s-k,R&7?32:10):s;D
R>0?B/2?H():getchar():R?.9+.7*M(R+1):0;}P t(N x,P K){D
x?(x>U?0:t(x+2,K)*(x-1)/x/K)+1/sqrt(K):t(2,K*K/U+1)*K;}N _(N J,N
x){F*(x?&W:&A)=W+J+x;(O=x=W/(J=k*k))||A<J||((O=2*W/J)&&2*A/J<3);A+=A-J+1){F
J*=x+O;S--*B&&x==O;O=x=!J){s+=x+s;M(0);}W+=W-J;S+=2;L+=L-J*k+M(S%8==B);}D
1;}P*p(P*J,P*x,P*O){F R=T;R--;)O[R]=J[R]+.8*x[R];D O;}P m(P*W,P*x,P s){F
R=U;--R;){P*A=W+R*U;W[R]+=s/12;*W+=s;*A-=*x++;F;A>W;){*A/=*W;F
O=R;O;O--)A[O]-=W[O]**A;A-=U;}W+=14;}D*W;}int main(int z,w*y){N
K=s,g;Y;M(z);s=B=C=15-H();s=G=M(8);s=l=M(C);G*=g=C%3?1:3;if(I=s=M(8)){N
b=G+9,x=b*340+U,J=b*(l+5),*n=V(N)*J),*j=n+5*b;P*h=V(P)*x),*q=h+b,*e=q+b;P
d=K;F;J--;)n[J]=J<b?0:I/2;F;x;)h[--x]=0;s=M(x);k=256;C=4-C;B=C/4;s=_(_(T,0),0);F;--z;){R=atoi(*++y);c=R>0?K=R,c:-2*R;}z=G/K+1;z+=g>z;I++;c++;F;++J<l;){P
u=0,C,y;P*H=e+U,*o=H+b*T,*r=o-2*T,*v=r-T;F;x<G;x++){p(H,o-T,o);o+=T;H+=T;q[x]=.7*(q[x-1]+h[x]);}p(H,H,r);F;x;){P*S=e;w
l=" !{   ,;lf6D@";j+=1-g;F;*++l;){*S++=*j;j+=*l%3*g-g+*l%5*b-3*b;}y=M(x-G);y=M(-J)*M(-x)+M(-J-1)*y+.01;y=sqrt((u+q[--x]+.1)/y);o-=T;C=i)+.5;K=M(-B);{N
f=I,Q=0;F;f-Q>c;){P l=0;N H=C+c/2+1;H%=c;H+=(f+Q+c-2*H)/2/c*c;l=Z(Q);O=(A-W)*Z(H)/Z(f);_(O,R=B?K>=H:L/k>O+W);*(R?&Q:&f)=H;}Q+=f;*S=*j=Q/=2;s=B?s:Q+k;f=Q+n[x/z];n[x/z]=x%z+J%(z*2/g)?f:!putc(x?l[4*g*f/z/z/I-8]:10,stderr);H-=U;F
O=156;O--;){H--;*H=e[O%U]*e[O/U]/y+.8**H;}C-=Q+.5;y=i/.9)-Q-C;p(p(r+T,r,r),H,r);h[x]=.7*h[x]+C*C;u+=h[x];u*=.7;d+=C>0?-y:y;}}j+=9;}_(_(x,x),x);}D 0;}
 
Back
Top