将用作睡眠的空for循环优化掉吗?

Fir*_*gon 8 c

我正在查看一些代码进行审核,并且遇到了繁忙的等待:

int loop = us*32;
int x;
for(x = 0;x<loop;x++)
{
    /*do nothing*/      
}
Run Code Online (Sandbox Code Playgroud)

我似乎记得读过这些空循环可以被优化掉.这是在这里发生的事情还是可以的?

oua*_*uah 15

答案是肯定的,编译器可以优化循环.

使用volatile限定符来避免优化:

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

如果您在嵌入式世界中进行编程,请阅读编译器的文档,因为它们通常提供等待参数中传递的特定循环或微秒的延迟函数.

例如,avr-gcc具有以下功能util/delay.h:

void _delay_us(double __us);
Run Code Online (Sandbox Code Playgroud)


cni*_*tar 12

你受编译器的支配.事实上,如果它很聪明,它会发现它是一个noop.顺便说一句,尼尔巴特沃思有一个很好的帖子,他也触及这个主题.

  • 如果启用优化. (3认同)

Adr*_*tti 5

这是非常不便携的东西.

在某些编译器中,其中一个可能有效(但是您必须检查启用完全优化,否则可能会丢弃空指令):

for (i = 0; i < spinCount; )
   ++i; // yes, HERE
Run Code Online (Sandbox Code Playgroud)

要么:

for (i = 0; i < spinCount; ++i)
   ((void)0);    
Run Code Online (Sandbox Code Playgroud)

如果你足够幸运,那么你的编译器可能会提供一个宏或一个内部函数,它将编译成nop汇编指令,类似于__noopMSVC.

作为最后一个资源,你可以简单地添加一个汇编指令(它依赖于编译器,它可能是__asm或类似的东西)来执行......没有,像这样:

for (i = 0; i < spinCount; ++i)
   __asm nop
Run Code Online (Sandbox Code Playgroud)

或(检查您的编译器文档):

for (i = 0; i < spinCount; ++i)
   asm("nop");
Run Code Online (Sandbox Code Playgroud)

编辑
如果你没有noop指令但你不能添加汇编代码(对不起,你正在使用什么样的编译器?)你可以依赖于一个带有副作用的指令不会被优化的假设离开(或者,由@ouah发布,对所声明的变量的访问volatile).


Cir*_*四事件 5

语言标准中没有任何内容禁止它,因此编译器如果有能力就可以这样做。

我们来反编译 GCC 4.8 看看它做了什么

输入代码:

int main() {
    int i;
    for(i = 0; i < 16; i++)
        ;
}
Run Code Online (Sandbox Code Playgroud)

编译和反编译:

gcc -c -g -std=c99 -O0 a.c
objudmp -S a.o
Run Code Online (Sandbox Code Playgroud)

输出:

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   
Run Code Online (Sandbox Code Playgroud)

循环就在那里:jle跳回来。

-O3

0000000000000000 <main>:
   0:   31 c0                   xor    %eax,%eax
   2:   c3                      retq
Run Code Online (Sandbox Code Playgroud)

它只返回 0。所以它被完全优化掉了。

可以对任何编译器进行相同的分析。

也可以看看


归档时间:

查看次数:

5931 次

最近记录:

10 年,8 月 前