Domanda

Mi chiedevo se esiste un modo pulito di contare da 0 a 255 usando un tipo di dati a 8 bit, qualcosa come:

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

Questo, ovviamente, non funzionerà, ma rende chiaro che si vuole contare da 0 a 255.

Una soluzione di lavoro sarebbe qualcosa di simile:

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

Ma qui non è affatto chiaro conta da 0 a 255.

Questo sarà anche il lavoro, ma è solo brutto IMHO:

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

Quindi mi chiedevo, c'è un modo pulito di fare questo senza usare un tipo di dati più grande?

EDIT:

  • Mi piace la versione che utilizza per perché rende la sua intenzione chiara senza pensare:. Loop da 0 a 255. Tutte le altre versioni richiedono qualche pensiero su ciò che sta succedendo e quindi più probabilità di confondere gli altri
  • Non voglio usare int perché il codice è per un microcontrollore a 8 bit con non molta memoria.
È stato utile?

Soluzione

Che dire:

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

Altri suggerimenti

Non sono sicuro di quello che vuoi dire, ma

 uint8_t i = 0;

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

dovrebbe fare ciò che si chiede e ha un riferimento esplicito a 255 (inutile se il compilatore è standard C99 e uint8_t è davvero 8 bit).

Cosa c'è di sbagliato con l'ovvio?

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

Sembra che tu voglia di trasmettere il messaggio di contare da 0 a 255 in base al tipo di dati che si sta utilizzando, ma qual è il significato di 255? Probabilmente si dovrebbe #define questo numero magico con un nome che indica in modo esplicito lo scopo di esso. Inoltre, un commento sopra l'istruzione sarebbe molto più utile che cercare di "codificare" tutte queste informazioni in looking statements un po 'strani.

Ad esempio:

#define MAX_RETRIES   255
unsigned int retries;

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

Se necessario, aggiungere un commento, perché il numero di tentativi è limitato a 255.

Vorrei suggerire che la soluzione più semplice:

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

è probabilmente anche andando a essere la soluzione più efficiente.

  1. Anche se si utilizza un (1 byte) tipo di dati più piccolo. Il compilatore C promuoverà a un int in ogni espressione.

  2. In un controller di 8 bit int è probabilmente 16 bit. Utilizzando un tipo singolo byte salverà solo un byte di spazio dello stack. Poi di nuovo il compilatore può mettere quella variabile in un registro, quindi non ci sarà alcun risparmio di spazio in ogni caso.

Controllare il codice assembly generato dal codice di cui sopra, quindi decidere se o non ha bisogno di (spazio) di ottimizzazione.

Conte in due metà?

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

Si spende così tanto sforzo per salvare un byte? Il tuo ultimo esempio potrebbe lavorare, o si potrebbe fare una sorta di combinazione tra la prima e la terza:

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

Ancora, chiedetevi se la bruttezza aggiunto nel codice vale la pena di risparmio che un byte. Se lo fai andare avanti con una soluzione del genere, probabilmente dovreste documentare il motivo per cui non si sta facendo il modo più ovvio.

Beh, se si vuole fare meno-che-chiaro il codice libero, si potrebbe sempre aggiungere un commento;)

Una soluzione è quella di posizionare il corpo del ciclo in una funzione (o una macro se la fustigazione pubblica non è un problema), e poi:

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

o se si preferisce non estendere il campo di i e applicare C ++ regole di visibilità:

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

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

Sembra perfettamente chiaro per me.

Anche se si sta cercando di utilizzare un contatore 1 byte, il compilatore può benissimo trasformarlo in questo, invece:

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

Per esempio, GCC fa, perché è più veloce.

$ 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, non c'è un modo chiaro per farlo in pianura vecchio C, come il condizionale è selezionata dopo l'incremento e se si confronta <= 255, si esegue un loop infinito, come un valore a 8 bit non può superare i 255 e terminare.

Così diventa.

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

A meno che non si pensa che il controllo contro 0 (vedere l'avvolgente) è chiaro nel tuo libro. Non è chiaro nella mia.

Si noti che i tipi a 8 bit sono molto inefficienti su molti compilatori, producendo segno inutili si estende a volte. Si potrebbe desiderare di utilizzare il tipo uint_least8_t invece, sarà probabilmente espandere la dimensione di parola del vostro sistema ed eseguire più veloce.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top