这是递归环境下的编译器优化吗
is this compiler optimization in context of recursion?
我使用尾部递归编写阶乘,这里有一个问题。我原来的功能看起来像这个
代码片段A
#include <stdio.h>
int main(void)
{
int n = 0;
printf("Enter number to find factorial of : ");
scanf("%d",&n);
printf("fact == %dn",fun(n,1));
return 0;
}
int fun(int n, int sofar)
{
int ret = 0;
if(n == 0)
return sofar;
ret = fun(n-1,sofar*n);
return ret;
}
然而,即使我不使用return,它仍然有效。这并不完全合理,因为我只在基本情况下返回值。假设n==5,则在基本情况下将返回120。但是,从第四次调用返回到第三次调用的内容无法预测,因为我们没有像代码片段A中那样明确指定任何返回。
代码段B
int fun(int n, int sofar)
{
int ret = 0;
if(n == 0)
return sofar;
ret = fun(n-1,sofar*n);
}
我认为上面的工作是因为某种编译器优化?因为如果我将printf语句添加到代码片段B中,它将不再工作。
代码片段C
int fun(int n, int sofar)
{
int ret = 0;
if(n == 0)
return sofar;
ret = fun(n-1,sofar*n);
printf("now it should not workn");
}
可能是printf导致某些东西从堆栈中删除?请帮我理解这一点。
不从应该返回值的函数返回值是未定义的行为。
如果运气好的话,那么这不是一个优化,而是这些自动分配的值是如何存储的以及存储在哪里的巧合。
我们可以推测为什么这是有效的,但没有办法给出明确的答案:在没有return
语句的情况下到达返回值函数的末尾并使用返回值是未定义的行为,无论是否进行优化。
这在编译器中"起作用"的原因是,编译器使用的返回机制恰好在函数结束时具有正确的值。例如,如果编译器在代码中最后一次计算所用的同一寄存器(即ret = fun(n-1,sofar*n)
(中返回整数,那么正确的值将意外加载到返回寄存器中,从而屏蔽未定义的行为。
它之所以有效,是因为返回值几乎总是存储在特定的CPU寄存器中(x86的eax
(。这意味着,如果不显式返回值,则不会显式设置返回寄存器。因此,它的值可以是任何值,但通常是最后一个调用函数的返回值。因此,用myfunc()
结束函数几乎可以保证具有与return myfunc();
相同的行为(但它仍然是未定义的行为(。
以下是计算"something"的原因。
对printf((的调用有一个返回值(很少使用(打印的字符数(包括制表符、换行符等(
在"C"代码段中,printf((返回23。
"int"返回的值总是在同一个寄存器中返回。
printf((将该寄存器设置为23。
因此,返回了一些内容,但没有从堆栈中删除任何内容。
它之所以在B中起作用,是因为返回值很可能是在架构上的寄存器中传递的。因此,通过递归的所有层返回(或者如果编译器将整个过程优化为迭代(,没有任何东西会触及该寄存器,您的代码似乎可以工作。
不同的编译器可能不允许这种情况发生,或者您的编译器的下一个版本可能会以不同的方式对此进行优化。事实上,编译器可以删除大部分函数,因为它可以假设,由于未定义的行为不会发生,这一定意味着函数中似乎发生未定义行为的部分永远不会到达,并且可以安全地删除。
- 如何解决gcc编译器优化导致的centos双编译器设置中的分段错误
- 使用仅使用一次的变量调用的复制构造函数.这可能是通过调用move构造函数进行编译器优化的情况吗
- 这个C++编译器优化(在自身的实例上调用对象自己的构造函数)的名称是什么,它是如何工作的?
- VS2017调试器:没有地址,可能是由于编译器优化
- 何时允许编译器优化复制构造函数
- 如何使用 GCC 编译器优化创建静态库?
- 为什么 std::chrono 在测量循环和编译器优化的并行 OpenMP 的执行时间时不起作用?
- 是否允许编译器优化掉局部易失性变量
- 删除编译器优化并在发布中启用 pdb 文件
- 静态 constexpr 的编译器优化
- 如何让MSVC编译器优化多步POD初始化?
- 按位不操作的编译器优化
- 模板专用化与编译器优化
- 编译器优化:G 比英特尔慢
- 运算符重载关联性编译器优化
- Intel OpenCL编译器:优化结构使用情况
- C 中编译器优化的影响
- 视觉C++ 2017 错误?编译器优化表达式
- 虚拟功能编译器优化C
- 未定义的行为确实有助于现代编译器优化生成的代码