清除使用8位数据类型从0到255计数的代码

时间:2009-11-10 13:03:20

标签: c embedded microcontroller

我想知道是否有一种使用8位数据类型从0到255计数的简洁方法,如:

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

这显然不起作用,但它清楚地表明你想从0到255计数。

一个有效的解决方案就是:

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

但是在这里它根本不清楚从0到255的数量。

这也可以,但它只是丑陋恕我直言:

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

所以我想知道,如果不使用更大的数据类型,有没有一种干净的方法呢?

编辑:

  • 我喜欢使用for的版本,因为它在不考虑的情况下使其意图清晰:从0循环到255.所有其他版本需要考虑一下发生了什么,因此更容易混淆其他版本。
  • 我不想使用int,因为代码是用于内存不多的8位微控制器。

10 个答案:

答案 0 :(得分:21)

怎么样:

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

答案 1 :(得分:8)

我不确定你的意思,但

 uint8_t i = 0;

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

应该按照你的要求做,并且明确引用255(如果编译器是C99标准且uint8_t真的是8位,则无用)。

答案 2 :(得分:5)

显而易见的是什么问题?

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

答案 3 :(得分:2)

您似乎想通过您正在使用的数据类型传达从0到255计数的消息,但255的重要性是什么?您应该#define这个神奇的数字,并明确说明其目的。此外,声明上方的评论比尝试在某些奇怪的陈述中“编码”所有信息更有帮助。

例如:

#define MAX_RETRIES   255
unsigned int retries;

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

如果需要,请添加注释,为什么重试次数限制为255次。

答案 4 :(得分:2)

我建议这个简单的解决方案:

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

可能也是最有效的解决方案。

  1. 即使您使用较小的(1字节)数据类型。 C编译器会将其提升为任何表达式中的int。

  2. 在8位控制器上,int可能是16位。使用单字节类型只能节省一个字节的堆栈空间。然后编译器可能会将该变量放入寄存器中,因此无论如何都不会节省空间。

  3. 检查上面代码生成的汇编代码,然后决定是否需要(空间)优化。

答案 5 :(得分:0)

算上两半?

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

答案 6 :(得分:0)

你花了这么多努力来保存一个字节? 你的最后一个例子是可行的,或者你可以做第一个和第三个的某种组合:

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

尽管如此,问问自己代码中增加的丑陋是否值得保存一个字节。 如果你继续这样的解决方案,你可能应该记录为什么你没有这么做的明显方法。

答案 7 :(得分:0)

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

对我来说非常清楚。

即使您尝试使用1字节计数器,您的编译器也可以将其转换为:

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

例如,GCC确实如此,因为它更快。

$ 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>

答案 8 :(得分:0)

如果你想清除不太清晰的代码,你可能总是添加评论;)

一种解决方案是将循环体放在一个函数中(如果不考虑公共鞭,则为宏),然后:

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

或者如果您不想扩展i的范围并且适用C ++范围规则:

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

答案 9 :(得分:0)

不,在普通旧C中没有明确的方法,因为在增量后检查条件,如果比较&lt; = 255,你将永远循环,因为8位值不能超过255并终止

所以它变成了。

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

除非你认为在你的书中清楚地检查0(看到环绕)。我的目前尚不清楚。

请注意,8位类型在许多编译器上效率非常低,有时会产生不必要的符号扩展。您可能希望使用uint_least8_t类型,它可能会扩展到系统的字大小并且运行得更快。