例如,如果我有这段代码:
var updatedNormalizedValue: Float
@IBAction func valuechanged(_ slider: UISlider) {
let min = slider.minimumValue
let max = slider.maximumValue
let interval = max - min
updatedNormalizedValue = (slider.value - min) / interval
}
让我们考虑可能等效代码:
class SomeDataProcessor
{
public:
bool calc(const SomeData & d1, const SomeData & d2) const;
private:
//Some non-mutable, non-static member variables
}
SomeDataProcessor sdp;
SomeData data1;
SomeData data2;
someObscureFunction(sdp.calc(data1, data2),
sdp.calc(data1, data2));
为了使其有效,bool b = sdp.calc(data1, data2);
someObscureFunction(b,b);
函数应满足某些要求,例如我调用属性calc()
_pure_const_formula_
会:
_pure_const_formula_
个函数例如,调用随机数生成器不符合这些要求。
编译器是否允许用第二个代码替换第一个代码,即使它需要递归地挖掘到被调用的函数中?现代编译器能够做到这一点吗?
答案 0 :(得分:46)
GCC的pure
attribute(用作__attribute__((pure))
)用于告诉编译器可以消除冗余调用的函数。它用于例如在strlen
。
我不知道有任何编译器会自动执行此操作,特别是考虑到要调用的函数可能无法以源格式提供,并且目标文件格式不包含有关函数是纯函数还是不。
答案 1 :(得分:22)
是的,绝对。
Compilers do this all the time, and more
例如,如果您的所有函数都返回true
,并且其定义对于调用点处的编译器是可见的,那么整个函数调用可能会被省略,从而导致:
someObscureFunction(true, true);
编译器具有足够信息的程序可以从非常复杂的任务链“优化”到可能一个或两个指令。现在,实际操作成员变量正在将优化器推到某种程度,但如果变量是private
,则给出一个已知的初始值,并且不会被任何其他成员函数变异,我不会看看为什么编译器不能只是想要内联它的已知值。编译器非常非常聪明。
人们认为编译的程序是源代码中行的一对一映射,但这几乎不是真的。 C ++的全部目的是它是计算机在运行程序时实际要做的抽象。
答案 2 :(得分:10)
不,鉴于显示的代码,编译器无法保证建议的优化没有可观察到的差异,并且现代编译器也无法优化第二个函数调用。
一个非常简单的例子:这个类方法可能使用随机数生成器,并将结果保存在某个私有缓冲区中,稍后会读取其他部分代码。显然,消除函数调用现在导致在该缓冲区中放置的随机生成的值更少。
换句话说,仅仅因为类方法const
并不意味着它在被调用时没有可观察到的副作用。
答案 3 :(得分:4)
不,在这种情况下,编译器不允许这样做。 const
仅表示您不更改方法所属对象的状态。但是,使用相同的输入参数多次调用此方法可能会产生不同的结果。例如,考虑一种产生随机结果的方法。
答案 4 :(得分:1)
是的,现代C编译器可以忽略冗余函数调用当且仅当他们可以证明这样的优化行为 as
现在,您具体询问了const
- 这对开发人员而非编码人员非常有用。 const
函数是一个提示,该方法不会修改它所调用的对象,而const
参数是提示那些参数没有修改。但是,该函数可能(合法地 1 )抛弃const
指针或其参数的this
- ness。所以编译器不能依赖它。
此外,即使传递给函数的const
对象确实从未在该函数中被修改过,并且const
函数从未修改过接收器对象,该方法也很容易依赖于可变的全局数据(并且可能改变这样的数据)。例如,考虑一个返回当前时间的函数,或者递增全局计数器的函数。
因此const
声明有助于程序员,而不是编译器 2 。
但是,编译器可能能够使用其他技巧来证明调用是多余的:
pure
和const
函数属性,通知gcc
函数没有副作用,并且仅依赖于它们的参数(以及全局变量,如果是pure
)。 1 通常,只要对象最初未定义为const
。
2 从某种意义上说,const
定义可以帮助编译器:它们可以将定义为const
的全局对象放入只读部分可执行文件(如果存在这样的特征)并且当它们相等时也组合这些对象(例如,相同的字符串常量)。