相同的 c 和 c++ 程序之间的巨大速度差异



我对 c 和 c++ 编程很陌生,所以我从基础知识开始。 我为 c 和 c++ 编写了相同的斐波那契循环程序来测试相对速度。 我以为对于这么简单的事情,它们会大致相同,但 c++ 版本慢了 60 倍。 他们所做的只是循环播放并打印前 14 个斐波那契数 10,000 次。 这是 c 版本:

#include <stdio.h>
int main (){
int c = 0;
int x, y, z;
while(c < 10000)
{
x = 0;
y = 1;
while(x < 255)
{
printf("%dn", x);
z = x + y;
x = y;
y = z;
}
c++;
}
return 0;
}

这是 C++ 版本:

#include <iostream>
using namespace std;
int main()
{
int c = 0, x = 0, y = 0, z = 0;
while(c < 10000)
{
x = 0;
y = 1;
while(x < 255)
{
cout << x << endl;
z = x + y;
x = y;
y = z;
}
c++;
}
return 0;
}

我用记事本++编写了它们,并使用代码块附带的mingw中的g++编译了它们:

g++ -o fibc.exe fib.c -s
g++ -o fibcpp.exe fib.cpp -s

可执行文件的大小非常不同:c 是 8.5KB,c++ 是 784KB!我使用powershell来计时:

Measure-Command {start-process "C:Pathfibcpp.exe" -RedirectStandardOutput "C:Pathcpp.txt" -Wait}

生成的文件相同,但 c 版本需要 1 秒,c++ 版本需要 60 秒!(事实上,为 c 程序放置 100 万的循环仍然只需要 13 秒)。我还在Visual Studio 17中编写了c ++,并使用x86发布配置对其进行了编译。 程序大小现在为 9.5KB,但运行时间与 g++ 版本相同:62 秒。 为什么这么简单的程序会发生这种情况?

您正在对printfcout进行基准测试,因为这些是程序中的主要瓶颈。

printf是一个非常慢的功能,但可能仍然比osteam快,必须维护自己的模板元编程的私人地狱,以使其像C++标准所要求的那样灵活。cout绝对比printf灵活和复杂得多。更多的功能意味着更慢的代码。

如果您真的想比较这两种语言,请删除打印功能并将它们替换为带有外部链接的虚拟函数"foo":

void foo (int x);
...
while(x < 255)
{
foo(x);

当使用 gcc -O3 对 x86 的代码进行基准测试时,我得到的 C 版本和C++版本代码几乎相同。

唯一值得注意的区别是C++main()末尾添加的"CRT"粘性。它调用 atexit 和 C 也会执行的各种其他清理,但可能在应用程序代码之外。C++中仍然会有开销,因为它必须调用具有静态存储持续时间的对象的构造和清理析构函数。C 不必这样做。

这里解释了C++cout速度慢的原因。

默认情况下,iostream 对象和 cstdio 流是同步的(就好像这个函数是用 true 作为参数调用的)。

因此,默认情况下,cout与stdio同步。

尝试执行以下命令以加快速度。

ios_base::sync_with_stdio(false)

但请注意,此代码将打印您意想不到的内容。

#include <iostream>
#include <cstdio>
int main()
{
std::ios::sync_with_stdio(false);
std::cout << "an";
std::printf("bn");
std::cout << "cn";
}

编译

#include <iostream>
using namespace std;
int main()
{
ios_base::sync_with_stdio(false);
int c = 0, x = 0, y = 0, z = 0;
while(c < 10000)
{
x = 0;
y = 1;
while(x < 255)
{
cout << x << 'n';
z = x + y;
x = y;
y = z;
}
c++;
}
return 0;
}

通过基本的现代优化(-Os)获得

$ ls -l bin/c?
-rwxr-xr-x 1 jthill jthill 16592 Feb 29 12:47 bin/c1
-rwxr-xr-x 1 jthill jthill 17176 Feb 29 12:53 bin/c2
-rwxr-xr-x 1 jthill jthill 17088 Feb 29 12:49 bin/c3
$ 

(你的C版本是c1,你的C++版本是c2,上面的C++版本是c3)。

平均每次运行 100 次的时间,

$ for x in {1..100}; do time bin/c1; done 2>&1 >$scratch | awk '/user/{++n; sub(/0m/,"",$2); tot+=$2}END{print tot/n}'
0.00862
$ for x in {1..100}; do time bin/c2; done 2>&1 >$scratch | awk '/user/{++n; sub(/0m/,"",$2); tot+=$2}END{print tot/n}'
0.0428
$ for x in {1..100}; do time bin/c3; done 2>&1 >$scratch | awk '/user/{++n; sub(/0m/,"",$2); tot+=$2}END{print tot/n}'
0.00743

如果使用得当,C++的iostreams比C的stdio更快

最新更新