为什么包含iostream时此代码更快?

Why is this code faster when iostream is included?

本文关键字:代码 包含 iostream 为什么      更新时间:2023-10-16

>更快的代码:

#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("%lin", 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("%lin", res);
return 0;
}

两者之间的唯一区别是第二行#include <iostream>

两者都使用 clang++ 8.0.0-3 编译,带有 -O2 标志。

clang++-8 -O2 fib.cpp && time ./a.out    # 3.59s
clang++-8 -O2 fib_io.cpp && time ./a.out # 3.15s

编辑:
重新启动后行为似乎发生了变化,这次iostream版本更慢,这更有意义。
我倾向于说这只是一种侥幸,因为我无法再重现它了。

当你包括#include <iostream>时,至少有一个副作用:必须构造和破坏std::ios_base::Init的实例(参见C++草案[ios.init]p1):

Init描述了一个对象,其构造可确保构造在<iostream>中声明的八个对象([iostream.objects]),这些对象将文件流缓冲区与<cstdio>中声明的函数提供的标准 C 流相关联。

来自cpp首选项的解释:

此类用于确保默认的C++流(std::cinstd::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都会有一些副作用,使整个程序对您来说更快。