Sign in to follow this  

Incrementing operators

This topic is 2814 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

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 this post


Link to post
Share on other sites
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 this post


Link to post
Share on other sites
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 this post


Link to post
Share on other sites
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 this post


Link to post
Share on other sites
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 this post


Link to post
Share on other sites
Quote:
Original post by Palidine
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:

*** 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 this post


Link to post
Share on other sites
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

Share this post


Link to post
Share on other sites
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 this post


Link to post
Share on other sites
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 this post


Link to post
Share on other sites
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 this post


Link to post
Share on other sites
Quote:
Original post by taz0010
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


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.

Share this post


Link to post
Share on other sites

This topic is 2814 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this