Reputation: 6055
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:
Upvotes: 8
Views: 4805
Reputation: 100648
I would suggest that the simple solution:
for (int i = 0; i < 256; ++i) {
...
}
is probably also going to be the most efficient solution.
Even if you use a smaller (1-byte) data type. The C compiler will promote it to an int in any expression.
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.
Upvotes: 2
Reputation: 1280
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.
Upvotes: 0
Reputation: 204718
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>
Upvotes: 0
Reputation: 93476
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) ;
Upvotes: 0
Reputation: 13059
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.
Upvotes: 2
Reputation: 10119
What's wrong with the obvious?
i = 255;
do {
work();
} while (i--);
Upvotes: 5
Reputation: 3757
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.
Upvotes: 0
Reputation: 16512
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).
Upvotes: 8
Reputation: 108978
Count in two halves?
uint8_t k = 0;
while (k & 0x80 == 0) {
work();
k++;
}
while (k & 0x80 == 1) {
work();
k++;
}
Upvotes: 0