views:

485

answers:

10

I was wondering if there is a clean way of counting from 0 to 255 using an 8 bit datatype, something like:

for(uint8_t i(0);i<=255;++i)
{
    ....
}

This obviously will not work but it makes it clear you want to count from 0 to 255.

A working solution would be something like:

uint8_t i(0);
do
{
    ...
    ++i;
}
while(i > 0);

But here it is not at all clear it counts from 0 to 255.

This will also work but it is just ugly IMHO:

uint8_t i(0);
while(true)
{
    ...
    if (i == 255)
    {
        break;
    }
    ++i;
}

So I was wondering, is there a clean way of doing this without using a larger datatype?

EDIT:

  • I like the version using for because it makes its intend clear without thinking: looping from 0 to 255. All other versions require some thought about what is going on and therefore more likely to confuse others.
  • I do not want to use int because the code is for a 8-bit microcontroller with not much memory.
A: 

Count in two halves?

uint8_t k = 0;
while (k & 0x80 == 0) {
  work();
  k++;
}
while (k & 0x80 == 1) {
  work();
  k++;
}
pmg
why are you doing this ?
Charles Faiga
Just another option to do something for 256 times. I wouldn't use it in real code.
pmg
+7  A: 

I'm not sure what you mean but

 uint8_t i = 0;

 do {
    ...
 } while (++i & 255) ;

should do what you ask and has an explicit reference to 255 (useless if your compiler is C99 standard and uint8_t is really 8 bits).

Remo.D
+1 I like this! I might even remove the 255: `uint8_t i = 0; do { work(); } while (++i);`
pmg
What did you think "using 8-bit datatype" in the title meant? :-) Of course it's really 8 bits.
paxdiablo
@paxdiablo: Sadly I've seen compilers taking some liberty on types. Hopefully this is no longer the case and one can trust uint8_t to round up to 0 after 255 :). Actually a good compiler should eliminate the and with 0xFF so it wouldn't harm to leave it (just in case)...
Remo.D
I like this one, but I like ots version better because it can also count to other values besides 255
rve
The C compiler (Tasking) for the Freescale DSP563XX processor uses a native 24 bit processor word for the char type. It will not wrap from 255 to zero unless you add an obscure compiler option that adds an explicit check each time that the value is incremented. The cost of this check on all char operations in code size and processing time is horrific. Not all processors are x86 or ARM
Ian
Remo.D
A: 

You spend this much effort to save one byte? Your last example would work, or you could do some sort of combination of the first and third:

for (uint8_t i = 0;;++i)
{
   work();
   if (i == 255)
       break;
}

Still, ask yourself if the added ugliness in the code is worth saving that one byte. If you do go along with a solution like that, you probably should document why you are not doing it the obvious way.

Mattias Nilsson
that is the problem, I want to save one byte (tiny microcontroller) but I still want to have clear code
rve
OK, but then you might need to actually check the code that is generated. It is possible that you're actually losing the space in generated code instead. Using one less byte for data storage doesn't guarantee that you actually save any space in the end.
Mattias Nilsson
+15  A: 

What about

uint8_t i = 0;
do {
 ...
} while (i++ != 255);

?

ot
this is what I was looking for, thanks
rve
+4  A: 

What's wrong with the obvious?

i = 255;
do {
 work();
} while (i--);
Dipstick
+1 Nothing wrong ... I like this best! :)
pmg
You are 45sec faster ;-).
Roman Nikitchenko
By the way this is what many ARM programmers use because of ARM specifics.
Roman Nikitchenko
What's wrong with it? How about the fact that you're counting backwards and his requirements said 0 to 255.
senfo
@senfo: So replace all uses of `i` within the loop by `~i`. No more problem!
ephemient
+1  A: 

You seem to want to convey the message of counting from 0 to 255 by the data type you are using, but what's the significance of 255? You should probably #define this magic number with a name explicitly stating the purpose of it. Also, a comment above the statement would be way more helpful than trying to "encode" all that information in somewhat weird looking statements.

For example:

#define MAX_RETRIES   255
unsigned int retries;

for(retries = 0; retries <= MAX_RETRIES; ++retries)
{
  do_retry_work();
}

If needed, add a comment, why the number of retries is limited to 255.

cschol
no, I do not want to convey the message by the data type. I want to convey the message it is counting from 0 to 255 while using the smallest possible data type without using complex constructions.
rve
A: 
ephemient
yes, it is clear, except that it is an infinite loop
rve
Ooh, hmm. Need more coffee.
ephemient
A: 

Well if you want to make less-than-clear code clear, you might always add a comment ;)

One solution is to place the body of the loop in a function (or macro if public flogging is not a concern), and then:

uint8_t i ;
for( i = 0; i < 255; i++ )
{
    body(i) ;
}
body(i) ;

or if you'd rather not extend the scope of i and C++ scope rules apply:

for( uint8_t i = 0; i < 255; i++ )
{
    body(i) ;
}
body(255) ;
Clifford
A: 

No, there's no clear way to do it in plain old C, as the conditional is checked after the increment and if you compare <= 255, you will loop forever, as an 8-bit value cannot exceed 255 and terminate.

So it becomes.

uint8_t i = 0;
while (1)
{
  /* your stuff */
  if (255 == i++)
    break;
}

Unless you think that checking against 0 (seeing the wraparound) is clear in your book. It's not clear in mine.

Note that 8-bit types are very inefficient on many compilers, producing unnecessary sign extends at times. You might want to use the uint_least8_t type instead, it'll likely expand to the word size of your system and run quicker.

Southern Hospitality
+1  A: 

I would suggest that the simple solution:

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

is probably also going to be the most efficient solution.

  1. Even if you use a smaller (1-byte) data type. The C compiler will promote it to an int in any expression.

  2. On an 8-bit controller an int is probably 16-bits. Using a single-byte type will only save one byte of stack space. Then again the compiler may put that variable in a register, so there will not be any space savings anyway.

Check the assembly code generated by the above code, then decide whether or not it needs (space) optimization.

Ferruccio