私はレビューするためにいくつかのコードを探しています、そしてそのように忙しい待機に出くわしました:
int loop = us*32;
int x;
for(x = 0;x<loop;x++)
{
/*do nothing*/
}
これらの空のループを最適化できることを読んだことを思い出しているようです。これはここで何が起こるのでしょうか、それともこれでうまくいくのでしょうか?
私はレビューするためにいくつかのコードを探しています、そしてそのように忙しい待機に出くわしました:
int loop = us*32;
int x;
for(x = 0;x<loop;x++)
{
/*do nothing*/
}
これらの空のループを最適化できることを読んだことを思い出しているようです。これはここで何が起こるのでしょうか、それともこれでうまくいくのでしょうか?
答えは「はい」です。コンパイラーはループを最適化できます。
修飾子を使用して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);
あなたはコンパイラに翻弄されています。確かに、それが賢い場合、それはヌープであることを検出します。ちなみに、ニール・バターワースには、このテーマについても触れている素晴らしい投稿があります。
それはひどく携帯できないものです。
一部のコンパイラでは、これらのいずれかが機能する場合があります(ただし、完全最適化を有効にしてチェックする必要があります。空の命令が破棄される場合があります)。
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
)。
言語標準にはそれを禁止するものはないので、コンパイラーは可能であればそれを行うことができます。
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を返すだけです。したがって、完全に最適化されています。
どのコンパイラでも同じ分析を行うことができます。
も参照してください
gccのような一部のコンパイラは、それが空のforループであることを検出し、遅延ループとしてそこに配置することを期待して、特にそのために悲観的になります。詳細については、 http: //gcc.gnu.org/onlinedocs/gcc-4.7.0/gcc/Non_002dbugs.htmlを参照してください。
これはコンパイラ固有であるため、すべてのコンパイラで信頼しないでください。