使用goto进行优化
Using goto for optimization
嗨,我想知道使用goto是否是优化的好方法。我知道这样做很野蛮,但说真的。
例如,写这个:
switch(command[0].cmd)
{
case 0: // turn off
s::s_off();
S_time = command[0].length;
break;
case 1: // turn on
s::s_on();
S_time = command[0].length;
break;
case 4: // nop
break;
}
像这样:
switch(command[0].cmd)
{
case 0: // turn off
s::s_off();
goto a;
break;
case 1: // turn on
s::s_on();
goto a;
break;
case 4: // nop
goto b;
break;
}
a:
S_time = command[0].length;
b:
事实上,如果可能的话,最好避免goto
,并相信编译器会为您进行优化。即使在您的情况下,也有一种避免代码重复的替代方案:
/*possibly inline*/ void foo(/*pass necessary parameters*/)
{
switch(command[0].cmd){
case 0: // turn off
s::s_off();
break;
case 1: // turn on
s::s_on();
break;
case 4: // nop
return;
}
S_time = command[0].length;
}
就优化而言,评测是最好的选择。但让我们看看生成的程序集,因为这也很有用。我将使用以下伪声明:
namespace s {
void s_on();
void s_off();
};
struct Command {
int cmd;
int length;
};
int S_time;
在-O3
使用Clang编译的代码的第一个版本产生:
foo(Command*): # @foo(Command*)
push rbx
mov rbx, rdi
mov eax, dword ptr [rbx]
cmp eax, 1
je .LBB0_3
test eax, eax
jne .LBB0_5
call s::s_off()
jmp .LBB0_4
.LBB0_3:
call s::s_on()
.LBB0_4:
mov eax, dword ptr [rbx + 4]
mov dword ptr [rip + S_time], eax
.LBB0_5:
pop rbx
ret
而第二个版本,带有goto
,产生:
foo2(Command*): # @foo2(Command*)
push rbx
mov rbx, rdi
mov eax, dword ptr [rbx]
cmp eax, 4
je .LBB1_6
cmp eax, 1 # These two instructions
je .LBB1_4 # weren't here in the first version
test eax, eax
jne .LBB1_5
call s::s_off()
jmp .LBB1_5
.LBB1_4:
call s::s_on()
.LBB1_5:
mov eax, dword ptr [rbx + 4]
mov dword ptr [rip + S_time], eax
.LBB1_6:
pop rbx
ret
虽然没有其他一些情况那么清楚,但有一个区别:第一个版本只将command[0].cmd
与0
和1
进行比较,但第二个版本将其与0
、1
和4
进行比较。更少的代码重复并不一定意味着更优化的代码:您实际上阻碍了优化器,并使其为4
生成了一个无用的特例。
goto
并不是批评者所描述的那种充满魔力的低级别优化光环的低级别工具。它只是一个非常基本的流量控制工具,在C++中很少使用(但仍然有一些!),而其他工具没有使用它。当然,它可以用于优化,但并不比其他任何工具更好或更容易。
不建议频繁使用goto
。但它不是"邪恶",在许多情况下,放1个后藤比更复杂的逻辑更容易,只是为了避免"邪恶"。在你的例子中,一个goto就足够了:
switch(command[0].cmd)
{
case 0: // turn off
s::s_off();
break;
case 1: // turn on
s::s_on();
break;
case 4: // nop
goto b; // break after goto is useless
}
S_time = command[0].length;
b:
goto
的使用应该是为了使代码更清晰。不是更复杂。这就是为什么,例如,跳出一组嵌套很深的循环,或者有时条件是否可以接受,但像本问题中的例子一样使用goto
来"优化"代码并不是一个特别好的原因——它并不能使代码更清晰,相反。
还有很多其他的解决方案——将一些东西分解成更小的函数(通常是一件好事)或重组代码。但是,如果由于"不惜一切代价避免goto",你最终得到了更复杂的代码,那么你可能走错了路。
这个问题举例说明了一种情况,即使用goto可能确实比问题本身选择的选项更好:有什么更好的方法可以避免do-while(0);用C++破解?
- 空基优化子对象的地址
- 关闭||运算符优化
- 如何解决gcc编译器优化导致的centos双编译器设置中的分段错误
- 返回值优化:显式移动还是隐式
- 人脸跟踪arduino代码的优化
- 使用仅使用一次的变量调用的复制构造函数.这可能是通过调用move构造函数进行编译器优化的情况吗
- 纯函数,为什么没有优化
- 为什么大多数 pair 实现默认不使用压缩(空基优化)?
- 如何以优化的方式同时迭代两个间距不相等的数组
- 在 ubuntu3 上C++ goto 定义有什么解决方案吗16.04?
- 小字符串优化(调试与发布模式)
- 浮点定向舍入和优化
- Visual Studio 调试优化如何工作?
- 如何正确指定 goto 语句的标签?
- 为什么开关的优化方式与 c/c++ 中的链接不同?
- 使用 goto 可以创建编译器无法在C++生成的优化吗?
- 使用goto进行优化
- Goto优化重构
- 通过将"goto"转换为分支机构进行优化
- goto 对C++编译器优化的影响