8

私はレビューするためにいくつかのコードを探しています、そしてそのように忙しい待機に出くわしました:

int loop = us*32;
int x;
for(x = 0;x<loop;x++)
{
    /*do nothing*/      
}

これらの空のループを最適化できることを読んだことを思い出しているようです。これはここで何が起こるのでしょうか、それともこれでうまくいくのでしょうか?

4

5 に答える 5

16

答えは「はい」です。コンパイラーはループを最適化できます。

修飾子を使用してvolatile、最適化を回避します。

int loop = us * 32;
volatile int x;
for (x = 0; x < loop; x++)
{
    /*do nothing*/      
}

組み込みの世界でプログラミングしている場合は、コンパイラのドキュメントを読んでください。通常、パラメータで渡される特定のサイクル数またはマイクロ秒数を待機する遅延関数が提供されます。

たとえばavr-gcc、次の関数がありますutil/delay.h

void _delay_us(double __us);
于 2012-04-24T15:08:58.077 に答える
14

あなたはコンパイラに翻弄されています。確かに、それが賢い場合、それはヌープであることを検出します。ちなみに、ニール・バターワースには、このテーマについても触れている素晴らしい投稿があります。

于 2012-04-24T14:42:09.780 に答える
5

それはひどく携帯できないものです。

一部のコンパイラでは、これらのいずれかが機能する場合があります(ただし、完全最適化を有効にしてチェックする必要があります。空の命令が破棄される場合があります)。

for (i = 0; i < spinCount; )
   ++i; // yes, HERE

また:

for (i = 0; i < spinCount; ++i)
   ((void)0);    

運が良ければ、コンパイラは、MSVCnopのように、アセンブリ命令にコンパイルされるマクロまたは組み込み関数を提供する場合があります。__noop

最後のリソースとして、実行する単一のアセンブリ命令(コンパイラに依存します。__ asmなど)を追加するだけで、次のようになります。

for (i = 0; i < spinCount; ++i)
   __asm nop

または(コンパイラのドキュメントを確認してください):

for (i = 0; i < spinCount; ++i)
   asm("nop");

編集
命令がなく、アセンブリコードを追加できない 場合noop(申し訳ありませんが、使用しているコンパイラの種類は?)、副作用のある命令は最適化されないという前提に頼ることができます。離れて(または、@ ouahによって投稿されたように、宣言された変数へのアクセスvolatile)。

于 2012-04-24T14:59:10.970 に答える
5

言語標準にはそれを禁止するものはないので、コンパイラーは可能であればそれを行うことができます。

GCC 4.8を逆コンパイルして、その機能を確認しましょう

入力コード:

int main() {
    int i;
    for(i = 0; i < 16; i++)
        ;
}

コンパイルと逆コンパイル:

gcc -c -g -std=c99 -O0 a.c
objudmp -S a.o

出力:

a.o:     file format elf64-x86-64


Disassembly of section .text:

0000000000000000 <main>:
int main() {
   0:   55                      push   %rbp
   1:   48 89 e5                mov    %rsp,%rbp
    int i;
    for(i = 0; i < 16; i++)
   4:   c7 45 fc 00 00 00 00    movl   $0x0,-0x4(%rbp)
   b:   eb 04                   jmp    11 <main+0x11>
   d:   83 45 fc 01             addl   $0x1,-0x4(%rbp)
  11:   83 7d fc 0f             cmpl   $0xf,-0x4(%rbp)
  15:   7e f6                   jle    d <main+0xd>
  17:   b8 00 00 00 00          mov    $0x0,%eax
        ;
}
  1c:   5d                      pop    %rbp
  1d:   c3                      retq   

ループがあります:それjleはジャンプバックします。

-O3

0000000000000000 <main>:
   0:   31 c0                   xor    %eax,%eax
   2:   c3                      retq

これは0を返すだけです。したがって、完全に最適化されています。

どのコンパイラでも同じ分析を行うことができます。

も参照してください

于 2015-06-26T11:39:37.997 に答える
2

gccのような一部のコンパイラは、それが空のforループであることを検出し、遅延ループとしてそこに配置することを期待して、特にそのために悲観的になります。詳細については、 http: //gcc.gnu.org/onlinedocs/gcc-4.7.0/gcc/Non_002dbugs.htmlを参照してください。

これはコンパイラ固有であるため、すべてのコンパイラで信頼しないでください。

于 2012-04-24T14:47:44.217 に答える