English 中文(简体)
clear code for counting from 0 to 255 using 8-bit datatype
原标题:

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.
最佳回答

What about:

uint8_t i = 0;
do {
    ...
} while (i++ != 255);
问题回答

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.





相关问题
Fastest method for running a binary search on a file in C?

For example, let s say I want to find a particular word or number in a file. The contents are in sorted order (obviously). Since I want to run a binary search on the file, it seems like a real waste ...

Print possible strings created from a Number

Given a 10 digit Telephone Number, we have to print all possible strings created from that. The mapping of the numbers is the one as exactly on a phone s keypad. i.e. for 1,0-> No Letter for 2->...

Tips for debugging a made-for-linux application on windows?

I m trying to find the source of a bug I have found in an open-source application. I have managed to get a build up and running on my Windows machine, but I m having trouble finding the spot in the ...

Trying to split by two delimiters and it doesn t work - C

I wrote below code to readin line by line from stdin ex. city=Boston;city=New York;city=Chicago and then split each line by ; delimiter and print each record. Then in yet another loop I try to ...

Good, free, easy-to-use C graphics libraries? [closed]

I was wondering if there were any good free graphics libraries for C that are easy to use? It s for plotting 2d and 3d graphs and then saving to a file. It s on a Linux system and there s no gnuplot ...

Encoding, decoding an integer to a char array

Please note that this is not homework and i did search before starting this new thread. I got Store an int in a char array? I was looking for an answer but didn t get any satisfactory answer in the ...