我正在查看一些代码进行审核,并且遇到了繁忙的等待:
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)
这是非常不便携的东西.
在某些编译器中,其中一个可能有效(但是您必须检查启用完全优化,否则可能会丢弃空指令):
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).
语言标准中没有任何内容禁止它,因此编译器如果有能力就可以这样做。
我们来反编译 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 次 |
| 最近记录: |