чистый код для подсчета от 0 до 255 с использованием 8-битного типа данных - PullRequest
8 голосов
/ 10 ноября 2009

Мне было интересно, есть ли чистый способ подсчета от 0 до 255 с использованием 8-битного типа данных, что-то вроде:

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

Так что мне было интересно, есть ли чистый способ сделать это без использования большего типа данных?

EDIT:

  • Мне нравится версия, используемая для for, потому что она ясно показывает свое намерение: цикл от 0 до 255. Все остальные версии требуют некоторого размышления о том, что происходит, и, следовательно, с большей вероятностью могут запутать других.
  • Я не хочу использовать int, потому что код предназначен для 8-битного микроконтроллера с небольшим объемом памяти.

Ответы [ 10 ]

21 голосов
/ 10 ноября 2009

А как же:

uint8_t i = 0;
do {
    ...
} while (i++ != 255);
8 голосов
/ 10 ноября 2009

Я не уверен, что вы имеете в виду, но

 uint8_t i = 0;

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

должен делать то, что вы просите, и имеет явную ссылку на 255 (бесполезно, если ваш компилятор соответствует стандарту C99, а uint8_t действительно 8 бит).

5 голосов
/ 10 ноября 2009

Что не так с очевидным?

i = 255;
do {
 work();
} while (i--);
2 голосов
/ 27 декабря 2009

Я бы предложил простое решение:

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

, вероятно, также будет самым эффективным решением.

  1. Даже если вы используете меньший (1 байт) тип данных. Компилятор C будет преобразовывать его в int в любом выражении.

  2. На 8-битном контроллере int, вероятно, 16-битный. Использование однобайтового типа сэкономит только один байт стекового пространства. Затем компилятор снова может поместить эту переменную в регистр, поэтому в любом случае не будет экономии места.

Проверьте код сборки, сгенерированный вышеуказанным кодом, затем решите, нуждается ли он в оптимизации (пробел).

2 голосов
/ 10 ноября 2009

Кажется, вы хотите передать сообщение о подсчете от 0 до 255 типом данных, который вы используете, но каково значение 255? Вероятно, вам следует # определить это магическое число с именем, явно указавшим его назначение. Кроме того, комментарий над утверждением был бы гораздо более полезным, чем попытка «закодировать» всю эту информацию в несколько странно выглядящих утверждениях.

Например:

#define MAX_RETRIES   255
unsigned int retries;

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

При необходимости добавьте комментарий, почему количество повторных попыток ограничено 255.

0 голосов
/ 11 ноября 2009

Нет, нет ясного способа сделать это на старом, старом C, так как условное выражение проверяется после приращения, и если вы сравниваете <= 255, вы будете выполнять цикл бесконечно, поскольку 8-битное значение не может превышать 255 и завершаться. </p>

Так и становится.

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

Если только вы не думаете, что проверка на 0 (видимость перехода) очевидна в вашей книге. По моему не ясно.

Обратите внимание, что 8-битные типы очень неэффективны на многих компиляторах, иногда создавая ненужные знаки расширения. Возможно, вы захотите использовать вместо этого тип uint_least8_t, он, вероятно, расширится до размера слова в вашей системе и будет работать быстрее.

0 голосов
/ 10 ноября 2009

Что ж, если вы хотите прояснить не совсем понятный код, вы всегда можете добавить комментарий;)

Одним из решений является помещение тела цикла в функцию (или макрос, если публичная порка не имеет значения), а затем:

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) ;
0 голосов
/ 10 ноября 2009

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>
0 голосов
/ 10 ноября 2009

Вы тратите столько усилий, чтобы сохранить один байт? Ваш последний пример сработает, или вы можете сделать какую-то комбинацию первого и третьего:

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

Тем не менее, спросите себя, стоит ли добавленное уродство в коде сохранять этот один байт. Если вы согласны с таким решением, вам, вероятно, следует задокументировать, почему вы не делаете это очевидным образом.

0 голосов
/ 10 ноября 2009

Считать пополам?

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