8

次のような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;
}

だから私は疑問に思っていました、より大きなデータ型を使用せずにこれを行うためのクリーンな方法はありますか?

編集:

  • を使用しているバージョンが好きなのは、0から255までループすることを考えずにその意図を明確にするためです。他のすべてのバージョンでは、何が起こっているかについてある程度考える必要があるため、他のバージョンを混乱させる可能性が高くなります。
  • コードはメモリの少ない8ビットマイクロコントローラ用であるため、intは使用しません。
4

10 に答える 10

21

どうですか:

uint8_t i = 0;
do {
    ...
} while (i++ != 255);
于 2009-11-10T13:23:20.123 に答える
8

どういう意味かわかりませんが

 uint8_t i = 0;

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

あなたが求めることを実行し、255への明示的な参照を持っている必要があります(コンパイラがC99標準であり、uint8_tが実際に8ビットである場合は役に立ちません)。

于 2009-11-10T13:16:10.013 に答える
5

明らかなことの何が問題になっていますか?

i = 255;
do {
 work();
} while (i--);
于 2009-11-10T13:24:59.350 に答える
2

使用しているデータ型で0から255まで数えるというメッセージを伝えたいようですが、255の意味は何ですか?おそらく、このマジックナンバーを、その目的を明示的に示す名前で#defineする必要があります。また、ステートメントの上のコメントは、そのすべての情報をやや奇妙な外観のステートメントに「エンコード」しようとするよりもはるかに役立ちます。

例えば:

#define MAX_RETRIES   255
unsigned int retries;

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

必要に応じて、再試行回数が255回に制限されている理由についてコメントを追加します。

于 2009-11-10T13:28:21.533 に答える
2

私は簡単な解決策を提案します:

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

おそらく最も効率的な解決策になるでしょう。

  1. より小さな(1バイト)データ型を使用する場合でも。Cコンパイラは、それを任意の式のintにプロモートします。

  2. 8ビットコントローラでは、intはおそらく16ビットです。シングルバイトタイプを使用すると、スタックスペースが1バイトしか節約されません。次に、コンパイラーはその変数をレジスターに入れる可能性があるため、とにかくスペースを節約することはできません。

上記のコードで生成されたアセンブリコードを確認し、(スペース)最適化が必要かどうかを判断します。

于 2009-12-27T14:24:02.067 に答える
0

2つに数えますか?

uint8_t k = 0;
while (k & 0x80 == 0) {
  work();
  k++;
}
while (k & 0x80 == 1) {
  work();
  k++;
}
于 2009-11-10T13:10:51.983 に答える
0

あなたは1バイトを節約するためにこれだけの努力を費やしますか?最後の例が機能するか、最初と3番目の組み合わせを行うことができます。

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

それでも、コードに追加された醜さがその1バイトを節約する価値があるかどうかを自問してください。そのような解決策を実行する場合は、おそらく、それを明白な方法で実行していない理由を文書化する必要があります。

于 2009-11-10T13:16:45.560 に答える
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:ファイル形式elf32-i386


セクション.textの逆アセンブル:

00000000 <バー>:
   0:55プッシュ%ebp
   1:89 e5 mov%esp、%ebp
   3:53プッシュ%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 $ 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:ファイル形式elf64-x86-64


セクション.textの逆アセンブル:

0000000000000000 <bar>:
   0:53プッシュ%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 $ 0x1、%ebxを追加
   d:e8 00 00 00 00 callq 12 <bar + 0x12>
  12:eb f4 jmp 8 <bar + 0x8>
于 2009-11-10T15:40:01.370 に答える
0

明確ではないコードを明確にしたい場合は、常にコメントを追加することができます;)

1つの解決策は、ループの本体を関数(または、パブリックのむち打ちが問題にならない場合はマクロ)に配置してから、次のようにすることです。

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) ;
于 2009-11-10T16:27:10.020 に答える
0

いいえ、単純な古いCでそれを行う明確な方法はありません。インクリメント後に条件がチェックされ、<= 255と比較すると、8ビット値が255を超えて終了することはできないため、永久ループになります。

だからなります。

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

あなたが0に対してチェックすること(ラップアラウンドを見る)があなたの本で明確であると思わない限り。私の場合ははっきりしていません。

多くのコンパイラでは8ビット型は非常に非効率的であり、不要な符号が生成される場合があることに注意してください。代わりにuint_least8_tタイプを使用することをお勧めします。システムのワードサイズに拡張され、より高速に実行される可能性があります。

于 2009-11-10T22:06:23.223 に答える