更快的代码:
#include <stdio.h>
#include <iostream>
long fib(int num)
{
if (num <= 1)
return 1;
else
return fib(num-1) + fib(num-2);
}
int main()
{
long res = fib(45);
printf("%li\n", res);
return 0;
}较慢的代码:
#include <stdio.h>
long fib(int num)
{
if (num <= 1)
return 1;
else
return fib(num-1) + fib(num-2);
}
int main()
{
long res = fib(45);
printf("%li\n", res);
return 0;
}两者之间唯一的区别是第二行的#include <iostream>。
两者都是使用带有-O2标志的clang++ 8.0.0-3编译的。
clang++-8 -O2 fib.cpp && time ./a.out # 3.59s
clang++-8 -O2 fib_io.cpp && time ./a.out # 3.15s编辑:
似乎重新启动后行为发生了变化,这次iostream版本变慢了,这会更有意义。
我倾向于说这只是一个偶然,因为我不能再复制它了。
发布于 2019-06-22 18:16:59
当您包含#include <iostream>时,至少有一个副作用:必须构造和析构std::ios_base::Init的实例(请参阅C++ draft [ios.init]p1):
类
Init描述了一个对象,它的构造确保了在<iostream>(iostream.objects)中声明的8个对象的构造,这些对象将文件流缓冲区与<cstdio>中声明的函数提供的标准C流相关联。
来自cppreference的解释
此类用于确保默认的C++流(
std::cin、std::cout等)被正确初始化和析构。该类跟踪创建了多少个实例,并在构造第一个实例时初始化C++流,并在最后一个实例被析构时刷新输出流。
头<iostream>的行为就像它(直接或间接)定义了一个具有静态存储持续时间的std::ios_base::Init实例:这使得通过有序初始化访问静态对象的构造函数和析构函数中的标准I/O流是安全的(只要#include <iostream>在定义这些对象之前包含在转换单元中)
这并不一定意味着性能应该不同(无论是更好还是更差)。然而,从C++标准的角度来看,这意味着你的两个程序是不相等的。
如果不查看给定标准库中的实际实现(或分析它),我们就无法知道详细原因(请随意添加答案!)。
在Linux机器上检查clang生成的代码(这似乎就是您的情况),即libstdc++
_GLOBAL__sub_I_a.cpp: # @_GLOBAL__sub_I_a.cpp
push rax
mov edi, offset std::__ioinit
call std::ios_base::Init::Init() [complete object constructor]
mov edi, offset std::ios_base::Init::~Init() [complete object destructor]
mov esi, offset std::__ioinit
mov edx, offset __dso_handle
pop rax
jmp # TAILCALL因此,无论是std::ios_base::Init::Init()还是__cxa_atexit都有一些副作用,会使整个程序运行得更快。
https://stackoverflow.com/questions/56714331
复制相似问题