# Incrementing operators

## Recommended Posts

Ectara    3097
I noticed that when I enabled nearest neighbor filtering, my textures showed up grayscale. I looked at the code I wrote, which appeared fine:
	ui8 *pix;
switch(src->format){
case E_RGB:
case E_ANIM_RGB:{
pix = src->data + (src->frameSize * src->currFrame) + 3*(src->width*(_E_mathRoundf(y)) + _E_mathRoundf(x));
return _E_eoiD1(*(pix++))|_E_eoiD2(*(pix++))|_E_eoiD3(*(pix))|_E_eoiD4(0xFF);
}
break;
...
}


The _E_eoiDn macros simply shift the passed value to be the nth byte in the integer. To me, it would seem that it would increment the pointer upon each evaluation of the variable. Apparently that isn't the case; the rewrite I wrote below showed the colors properly, rather than only using one channel for all three.
	ui8 *pix;
si32 result;
switch(src->format){
case E_RGB:
case E_ANIM_RGB:{
pix = src->data + (src->frameSize * src->currFrame) + 3*(src->width*(_E_mathRoundf(y)) + _E_mathRoundf(x));
memcpy(&result,pix,3);
return result|_E_eoiD4(0xFF);
}
break;
...
}


So, I suppose my question is, if I have multiple incrementing operators on the same variable at different parts of a statement, is it evaluated and incremented more than once in sequence as I'd expected, or does it do all of the increments prior to evaluating the entire expression?

##### Share on other sites
Palidine    1315
pix++ permanently adjusts the value of pix. So any sucessive access of pix will be of the modified value. They should be incremented in order. But why not just use (pix+1) and (pix+2) then do a pix+=3 at the apropriate time? Seems much more readable that way anyway

-me

##### Share on other sites
Palidine    1315
pix++ also means: use the value of pix then increment it.
++pix means: increment first then use the value.

But yeah... your statement is ridiculously confusing. Why not something like:

case E_ANIM_RGB:{    pix = src->data + (src->frameSize * src->currFrame) + 3*(src->width*(_E_mathRoundf(y)) + _E_mathRoundf(x));    ui8 r = *pix;    ui8 g = *(pix+1);    ui8 b = *(pix+2);    pix += 3;    return _E_eoiD1(r)|_E_eoiD2(g)|_E_eoiD3(b)|_E_eoiD4(0xFF);}

And also... why are you bitwise or'ing them together?

##### Share on other sites
Ectara    3097
pix is only twice once during this function; once to initialize, once to be evaluated in this returned expression. I've also read that increment operators require one instruction while adding a constant to a variable requires two. Since this function would be called once or twice for every pixel written for every polygon in my renderer, I figured every little bit counts. But the thing that confused me was, I incremented twice in the expression, and rather than incrementing and using the incremented values, it only used one value, as if it added two and used the last value for all three in the evaluation, or used the first then added two.

##### Share on other sites
Palidine    1315
don't optimize before your profiler tells you it's a problem. the compiler is better at optimizing than you anyway. your code is confusing and you can't debug it. make it clean with temp variables and trust that the compiler will make it fast. if it doesn't you can always come back and micro-oiptimze it later.

only pre-increment doesn't require a temp. you're doing post-increment. however, that is "old advice". The compiler will almost always optimize this for you.

-me

##### Share on other sites
Ectara    3097
Quote:
 Original post by Palidinepix++ also means: use the value of pix then increment it.++pix means: increment first then use the value.But yeah... your statement is ridiculously confusing. Why not something like:*** Source Snippet Removed ***And also... why are you bitwise or'ing them together?

That would add(assuming a typical stack), three push instructions to allocate the variables, three to assign them, the usual to reference them, then three to pop them off the stack. And I like to OR them together. On some arch's it is simpler than addition.

##### Share on other sites
Ectara    3097
Alright, I chose an alternate method, and I'm guessing the compiler added two and used the original value.

##### Share on other sites
Palidine    1315
Yeah. good plan [smile]

I mean, basically, every piece of advice you've ever heard about arranging code at a micro-level is something that was true maybe 10 years ago. Modern compilers in almost every respect are better than you at that kind of optimization. The only time you should ever worry about details like what you're talking about is if the profiler tells you that piece of code is slow and if you look at the generated assembly and realize that the optimizer has missed something.

-me

BFG    1301

##### Share on other sites
Ectara    3097
Thank you, BFG, for answering my question. I even remember reading that FAQ a while back. I'll avoid doing that from now on.

##### Share on other sites
Dragon88    246
Just to further the point that everyone else is making, with a modern optimizing compiler, those temporary variables are likely to be optimized right out. That means that their results never get written back into memory at all. The expression will just be evaluated exactly the same as it would be in your hyper-optimized, tedious-to-write, and impossible-to-read version.

##### Share on other sites
taz0010    277
This is interesting. Apparently whitespace makes a difference:
	int x = 2,y;	y = x + ++x; // Not the same as	y = x+++x; // Which is y = x++ + x;	y = x++ + ++x; // Undefined apparently, but gives the predictable answer in this case	y = x+++++x; // Won't compile this

##### Share on other sites
Zahlman    1682
Quote:
 Original post by taz0010This is interesting. Apparently whitespace makes a difference: int x = 2,y; y = x + ++x; // Not the same as y = x+++x; // Which is y = x++ + x; y = x++ + ++x; // Undefined apparently, but gives the predictable answer in this case y = x+++++x; // Won't compile this

That is because of how tokens are matched: scanning left-to-right, each time grabbing as much as possible that's still a valid token on the language. (Pretty much everyone does it this way, BTW.) Whitespace is "ignored", but it does force the end of a token, because no token of the language is allowed to include it.

Therefore 'x+++x' must be x ++ + x, and 'x+++++x' must be 'x ++ ++ + x', which can't compile.