Jump to content
  • Advertisement
Sign in to follow this  
aregee

For-loop-insanity

This topic is 1391 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

Advertisement

Classic mistake. There is a generic way to make it work, if you really want to, though:

uint8_t j = 0;

do
{
  printf("%i\n", j);
}
while (++j);

Which is pretty readable, since the while loop is clearly going to terminate as soon as j overflows. And like Ravyne said, it doesn't really make anything faster in general, that said I personally don't see this as an optimization tactic, but more as a type correctness thing, in other words, the loop variable is going to be used as an 8-bit unsigned integer, so let's not lie to ourselves, make it an 8-bit unsigned integer. But with this comes the responsibility of watching out for overflow and other low-level things which generally don't come up when simply using a sufficiently large signed integer like int, people will have their own opinions on that matter smile.png

 

edit: fixed the termination condition error, thanks

Share this post


Link to post
Share on other sites

I think we all have those moments sometimes. Figuring out why those loops would never terminate could possibly make for a very frustrating debug session. biggrin.png

Share this post


Link to post
Share on other sites

Classic mistake. There is a generic way to make it work, if you really want to, though:

uint8_t j = 0;

do
{
  printf("%i\n", j);
}
while (j++);

Which is pretty readable, since the while loop is clearly going to terminate as soon as j overflows. And like Ravyne said, it doesn't really make anything faster in general, that said I personally don't see this as an optimization tactic, but more as a type correctness thing, in other words, the loop variable is going to be used as an 8-bit unsigned integer, so let's not lie to ourselves, make it an 8-bit unsigned integer. But with this comes the responsibility of watching out for overflow and other low-level things which generally don't come up when simply using a sufficiently large signed integer like int, people will have their own opinions on that matter smile.png

Don't you mean ++j?

 

I just tried it on ARM7, which has only 32-bit registers, and it compiled to a compare with 256, branch if not equal. So it doesn't actually force the wrapping, but did get the logic correct, and no different than using an int and comparing with 256.

Share this post


Link to post
Share on other sites

Huh. I have ++j in my test source file, must've copied it wrong on the forum. Sorry about that, I will edit.

 


To be picky, this works, but it also leaks the loop counter into the surrounding scope (as a "correctness issue"), and might contribute to register pressure for the duration of the scope (as an "optimization issue", though I would hope a modern compiler would do better)

 

About leaking the loop counter in the surrounding scope, I am curious if there is an elegant way to achieve the same result with a for loop, so that the loop counter would be limited to the scope of the loop.

Share this post


Link to post
Share on other sites


I am curious if there is an elegant way to achieve the same result with a for loop, so that the loop counter would be limited to the scope of the loop.

 

Elegant, I don't think so. This is the least ugly thing I could come up with.

 

    for (uint8_t test = 1; test > 0; test++) {
      printf("%i\n", (test - 1));
    }

 

But please don't try this at home :)

 

You could also just create a scope around the variable definition and do-while in your example. It would limit the scope 'appropriately', but its ugly, non-idiomatic, and another programmer who comes along might be tempted to delete the extra braces and not think anything of it -- likely that just puts you back in the same potentially-sub-optimal boat as before, but it could break a build or change the behavior of the code if the variable name aliased another.

Share this post


Link to post
Share on other sites

The elegant way is to just use an int.

 

CPUs don't have 8bit registers, or don't want to operate on 8bit values these days, which means that when you write this:

uint8_t j = 0; do {...} while (++j);

You're actually asking the compiler to transform it into something like this abomination:
int j = 0; do {...} while( (j=(j+1)&0xFF) != 0 );

...and then also asking the compiler to try and optimize such horrible code for you!

 

After wasting a bunch of time optimizing your code, it will be the same as if you'd just written what DekuTree posted, which is a perfectly idiomatic loop without any clever obfuscation applied:

for( int i=0; i!=256; ++i ) {...}

 

If there is a more optimal way of looping on a specific platform, a clever compiler will be able to transform any of the above loops to it, seeing they're all exactly equivalent in behavior!

Edited by Hodgman

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

Participate in the game development conversation and more when you create an account on GameDev.net!

Sign me up!