我的问题是关于gcc
编译器。
通常,在循环中,我必须使用在整个循环期间保持不变的函数返回的值。
我想知道在变量中预先存储这个常量返回值是否更好(让我们设想一个长循环),或者像gcc
之类的编译器是否能够执行一些优化来缓存常量值,因为它会认为它不断地抛出循环。
例如,当我在字符串中循环字符时,我经常写这样的东西:
bool find_something(string s, char something)
{
size_t sz = s.size();
for (size_t i = 0; i != sz; i++)
if (s[i] == something) return true;
return false;
}
但是使用一个聪明的编译器,我可以使用以下(更短更清晰):
bool find_something(string s, char something)
{
for (size_t i = 0; i != s.size(); i++)
if (s[i] == something) return true;
return false;
}
然后编译器可以检测到循环内的代码没有对string
对象执行任何更改,然后构建一个代码来缓存s.size()
返回的值,而不是为每次迭代进行(较慢)函数调用。
gcc
是否有这样的优化?
答案 0 :(得分:2)
通常,您的示例中没有任何内容使编译器无法在循环之前移动android:padding="-20dp"
计算。实际上,GCC 5.2.0将为您展示的两种实现生成exactly the same code。
我强烈建议反对依赖于这样的优化(在真正的性能关键代码中)因为某处的小改动(GCC优化器,.size()
的实现细节,... )可能会破坏GCC进行优化的能力。
但是,我认为在通常的90%代码中编写更详细的版本并不是真正具有性能关键性。
鉴于目前的C ++编译器,我会更加简洁:
std::string
哪个BTW也会产生与GCC 5.2.0非常相似的机器代码。
答案 1 :(得分:1)
编译器必须知道对象未在不同的线程中修改。如果对象没有改变,它可以告诉函数不会改变,但是它不能告诉对象不会从其他刺激中改变。
如果您包含某种形式的整体程序优化,编译器将展开对具有大小的成员的调用
答案 2 :(得分:0)
这取决于编译器是否可以将函数调用识别为常量。请考虑以下可能驻留在外部库中的函数,该函数无法由编译器进行分析。
var spinner = $('<i class="fa fa-refresh fa-spin"></i>');
var button = $("#CMSub");
button.css({'width':button[0].clientWidth + 'px'});
function refreshreplace() {
button.text('');
button.append(spinner);
}
无论输入参数如何,此函数都将返回不同的值。因此,即使传递的字符串对象保持不变,编译器也不能假定常量返回值。不会进行任何优化。
另一方面,如果编译器检测到常量函数调用(在您的示例中可能就是这种情况),则可能会将常量表达式移出循环。
较早版本的int odd_size(string s) {
static int a = 0;
return a++;
}
有一个明确的选项gcc
,负责该任务。来自gcc-3.4.5 documentation:
-floop-优化
执行循环优化:将常量表达式移出循环,简化退出测试条件,并可选择执行强度降低和循环展开。
在-O,-O2,-O3,-Os等级启用。
我在-floop-optimize
的当前版本中找不到此选项,但我确信它们也包含此类优化。