Question

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.
Was it helpful?

Solution

What about:

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

OTHER TIPS

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).

What's wrong with the obvious?

i = 255;
do {
 work();
} while (i--);

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.

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.

Count in two halves?

uint8_t k = 0;
while (k & 0x80 == 0) {
  work();
  k++;
}
while (k & 0x80 == 1) {
  work();
  k++;
}

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.

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) ;

for (uint8_t i(0); (int)i <= 255; ++i)

Seems perfectly clear to me.

Even if you are trying to use a 1-byte counter, your compiler may very well turn it into this instead:

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

For example, GCC does, because it's faster.

$ cat >test.c
void foo(char);
void bar(void) {
    char i;
    for (i = 0; i <= 255; i++)
        foo(i);
}
^D
$ cc -m32 -c -O3 test.c
$ objdump -d test.o

test.o:     file format elf32-i386


Disassembly of section .text:

00000000 <bar>:
   0:   55                      push   %ebp
   1:   89 e5                   mov    %esp,%ebp
   3:   53                      push   %ebx
   4:   31 db                   xor    %ebx,%ebx
   6:   83 ec 04                sub    $0x4,%esp
   9:   8d b4 26 00 00 00 00    lea    0x0(%esi,%eiz,1),%esi
  10:   89 1c 24                mov    %ebx,(%esp)
  13:   83 c3 01                add    $0x1,%ebx
  16:   e8 fc ff ff ff          call   17 <bar+0x17>
  1b:   eb f3                   jmp    10 <bar+0x10>
$ cc -m64 -c -O3 test.c
$ objdump -d test.o

test.o:     file format elf64-x86-64


Disassembly of section .text:

0000000000000000 <bar>:
   0:   53                      push   %rbx
   1:   31 db                   xor    %ebx,%ebx
   3:   0f 1f 44 00 00          nopl   0x0(%rax,%rax,1)
   8:   89 df                   mov    %ebx,%edi
   a:   83 c3 01                add    $0x1,%ebx
   d:   e8 00 00 00 00          callq  12 <bar+0x12>
  12:   eb f4                   jmp    8 <bar+0x8>

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top