C/C++编译器是否会通过重用最近计算的函数结果来优化代码?
Will a C/C++ compiler optimise code by reusing a recently calculated function result?
>假设我有一个函数double F(double x)
,为了这个例子,让我们假设调用F
是昂贵的。
假设我编写一个函数f
来计算F
的平方根:
double f(double x){
return sqrt(F(x));
}
在第三个函数sum
我计算f
和F
之和:
double sum(double x){
return F(x) + f(x);
}
由于我想最大限度地减少对F
的调用,因此与例如
double sum_2(double x){
double y = F(x);
return y + sqrt(y);
}
但是由于我很懒惰,或者愚蠢,或者想让我的代码尽可能清晰,所以我选择了第一个定义。
C/C++编译器是否会通过意识到F(x)
的值可以重用于计算f(x)
来优化我的代码,就像在sum_2
中所做的那样?
非常感谢。
C/C++ 编译器是否会通过意识到 F(x) 的值可以重用于计算 f(x) 来优化我的代码,就像在 sum_2 中所做的那样?
或。 这两种语言都不需要这样的优化,它们是否允许取决于F()
实现的细节。 一般来说,不同的编译器在这类事情上的行为不同。
编译器将函数f()
内联到函数sum()
中是完全合理的,这将使它有机会认识到有两个调用F(x)
对相同的结果有贡献。 在这种情况下,如果F()
没有副作用,那么可以想象编译器只会发出一次调用F()
,重用结果。
特定的实现可能具有扩展,可用于帮助编译器得出这样的结论。 但是,如果没有这样的扩展应用于问题,我认为编译器不太可能发出仅执行一次调用F()
并重用结果的代码。
你所描述的称为记忆,一种(通常)运行时缓存的形式。虽然这可以在编译器中实现,但通常不会在 C 编译器中执行。
C++确实有一个聪明的解决方法,使用 STL,详见几年前的这篇博文;这里还有一个稍微更新的 SO 答案。值得注意的是,使用这种方法,编译器不会"聪明地"推断函数的多个相同结果将被重用,但效果大致相同。
某些语言(如 Haskell)确实具有对编译时记忆的内置支持,但编译器体系结构与 Clang 或 GCC/G++ 有很大不同。
许多编译器使用提示来确定是否可以重用先前函数调用的结果。一个经典的例子是:
for (int i=0; i < strlen(str); i++)
如果不对此进行优化,此循环的复杂度至少为 O(n2),但优化后它可以是 O(n)。
gcc,clang和许多其他人可以采取的提示是这里描述的__attribute__((pure))
和__attribute__((const))
。例如,GNUstrlen
被声明为纯函数。
GCC可以检测纯函数,并建议程序员哪些函数应该与纯函数结婚。实际上,对于以下简单示例,它会自动执行此操作:
unsigned my_strlen(const char* str)
{
int i=0;
while (str[i])
++i;
return i;
}
unsigned word_len(const char *str)
{
for (unsigned i=0 ; i < my_strlen(str); ++i) {
if (str[i] == ' ')
return i;
}
return my_strlen(str);
}
您可以使用-O3 -fno-inline
查看 gcc 的编译结果。它在整个word_len
函数中只调用my_strlen(str)
一次。Clang 7.0.0 似乎没有执行此优化。
word_len:
mov rcx, rdi
call my_strlen ; <-- this is the only call (outside any loop)
test eax, eax
je .L7
xor edx, edx
cmp BYTE PTR [rcx], 32
lea rdi, [rdi+1]
jne .L11
jmp .L19
.L12:
add rdi, 1
cmp BYTE PTR [rdi-1], 32
je .L9
.L11:
add edx, 1
cmp eax, edx
jne .L12
.L7:
ret
.L19:
xor edx, edx
.L9:
mov eax, edx
ret
- 递归函数计算序列中的平方和(并输出过程)
- 函数计算用户按下按钮的频率
- C++ 在编译时具有函数计算全局变量
- C++ - 使用特定函数计算 x 和 y 的最终值
- 尝试使用函数计算有剩余球员的球队数量
- 我正在尝试创建一个布尔函数,该函数计算字符并在字符为"()*-+"时返回 true
- 哈希函数计算
- 为什么 if 语句对于运算符重载函数计算 false
- 使用C 中的内在函数计算相交
- 如何使用 2 个迭代器进行求和函数计算映射<字符串、双精度>
- vector.size() 函数计算量大吗?
- 如何使用opencv函数计算图像的孔数(二进制)
- 斐波那契函数计算不正确
- 如何用3个用户定义的函数计算一个数字的真平方根
- 元函数计算 x^n 并返回整数限制而不溢出(如果不可能)
- 使用递归函数计算字符串中的元音
- 如何使用 pow() 函数计算 C++ 中超过 2^32 的幂
- 返回 void 的函数的无序函数计算
- 在 C++ 中使用尾递归函数计算列表的总和
- 使用结构和函数计算线的长度