让我们考虑用C编写的以下代码块:
void foo(int i) {
if(i > 0) {
bar(i);
}
}
static void bar(int i) {
if(i > 0) {
//Do something useful
printf("FOO-BAR");
}
}
一个好的主流C编译器可以优化不必要的 i> 0 与foo(int)内部调用的bar(int)的比较?
如果是,那么在什么情况下如果没有那么为什么不呢?
答案 0 :(得分:2)
它主要适用于程序的输出控制流程不依赖于运行时事件的情况(这是最常用的技术之一)。例如,这里不会进行优化,因为您永远不知道i
的价值是多少。但这肯定是,
static void bar(int i) {
i = 1;
if(i > 0) {
//Do something useful
printf("FOO-BAR");
}
}
此处无论下一次i>0
检查多余都是如此。而且,你总是应该生成组件并寻找它。编译器在这方面的优化可能非常具有攻击性。
此处还有另一件事需要注意 - 例如,编译器不会优化此代码 - 即使它总是用于大于0
值的参数。编译器无法预测这一点。
代码优化中最常见的技术涉及 - 检查数据流图,消除死代码,循环展开(在您的小例子中肯定不能非侵略性地应用)。
答案 1 :(得分:2)
标准允许它。
对于C语言,草案n1570在5.1.2.3程序执行中说明(强调我的)
1本国际标准中的语义描述描述了一个人的行为 优化问题无关的抽象机器。
4在抽象机器中,所有表达式都按语义指定进行计算。 <强>一种 实际实现不需要评估表达式的一部分,如果它可以推导出它 没有使用价值,也没有产生所需的副作用
对于C ++草案,n1659包含4.6程序执行[intro.execution]
1本国际标准中的语义描述定义了参数化的非确定性摘要 机。本国际标准对符合实施的结构没有要求。 特别是,它们不需要复制或模拟抽象机器的结构。相反,符合 实现需要模拟(仅)抽象机器的可观察行为,如上所述 below.6
...
5 执行格式良好的程序的符合实现应产生与之相同的可观察行为 具有相同程序的抽象机器的相应实例的可能执行之一 和相同的输入。但是,如果任何此类执行包含未定义的操作,则此国际 标准不要求使用该输入执行该程序的实现(甚至不是 关于第一次未定义操作之前的操作。)
答案 2 :(得分:2)
C ++编译器可以自由地进行任何不可观察的优化。优化器比大多数人想象的要切碎得多。 What Has My Compiler Done For Me Lately?在给定的情况下可能会发生的事情是foo
将被转换为:
void foo(int i) {
if(i > 0) {
printf("FOO-BAR");
}
}
这就是VC ++ 2017的功能。事实上,它优化了foo
和bar
,并且在给定以下MCVE时只执行一次测试。
static void bar(int i) {
if (i > 0) {
//Do something useful
printf("FOO-BAR");
}
}
void foo(int i) {
if (i > 0) {
bar(i);
}
}
int main() {
int i;
scanf("%d", &i);
foo(i);
}
以下是生成的程序集。请注意,从stdin读取int i
后,下一条指令是cmp
(比较),后跟jle
(如果小于或等于则跳转)。没有foo
或bar
在优化程序中幸存下来。
int main() {
000000013F401000 sub rsp,38h
000000013F401004 mov rax,qword ptr [__security_cookie (013F403000h)]
000000013F40100B xor rax,rsp
000000013F40100E mov qword ptr [rsp+28h],rax
int i;
scanf("%d", &i);
000000013F401013 lea rdx,[i]
000000013F401018 lea rcx,[string "%d" (013F402228h)]
000000013F40101F call scanf (013F401060h)
foo(i);
000000013F401024 cmp dword ptr [i],0
000000013F401029 jle main+37h (013F401037h)
000000013F40102B lea rcx,[string "FOO-BAR" (013F402220h)]
000000013F401032 call printf (013F4010D0h)
}
000000013F401037 xor eax,eax
000000013F401039 mov rcx,qword ptr [rsp+28h]
000000013F40103E xor rcx,rsp
000000013F401041 call __security_check_cookie (013F401140h)
000000013F401046 add rsp,38h
000000013F40104A ret