15

I'm very new to c and c++ programming, so I'm starting with the basics. I wrote identical Fibonacci loop programs for both c and c++ to test relative speed. I thought they'd be about the same for something so simple, but the c++ version is 60x slower. All they do is loop through and print the first 14 Fibonacci numbers 10,000 times. Here is the c version:

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

and here is the c++ version:

#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; } 

I wrote both in notepad++ and compiled them using g++ from the mingw that comes with codeblocks:

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

The executables are very different in size: the c is 8.5KB and the c++ is 784KB! I used powershell to time them:

Measure-Command {start-process "C:\Path\fibcpp.exe" -RedirectStandardOutput "C:\Path\cpp.txt" -Wait} 

The files produced are identical, but the c version took 1 sec and the c++ verison took 60sec! (In fact, putting a loop of 1 million for the c program still only took 13sec). I also wrote the c++ in Visual Studio 17 and compiled it there with an x86 release config. The program size is now 9.5KB, but the run time is the same as the g++ version: 62sec. Why is this happening for such a simple program?

18
  • 6
    Try to use the same header as the C code in the C++ code. Remove using namespace std; and use printf instead of cout and check again the difference between them. When you run such an experiment you should have the closests codes as you can. Commented Aug 23, 2019 at 11:08
  • 11
    Try using '\n' instead of std::endl for starters, you don't need to flush every time. Have you tryed to compile with optimizations, like e.g. -O2? Commented Aug 23, 2019 at 11:09
  • 11
    You're not comparing equivalent code. C++ streams (std::cout, etc) are synchronised with their C equivalents by default - which means a performance hit by default. Try doing std::ios::sync_with_stdio(false) before performing output - then the C++ version will be closer (albeit not completely equivalent) to the C version. Also, the endl stream manipulator flushes the stream buffer, which is not done when supplying a '\n' to printf(). Also, benchmarking is usually pointless on unoptimised code. Commented Aug 23, 2019 at 11:15
  • 1
    could you replace cout with printf? Commented Aug 23, 2019 at 11:15
  • 3
    Well, you guys solved my problem in 2 minutes- thank you. Switching to stdio and printf in the c++ code was everything- the new exe is the same size and performance as the c version. As you can see, I'm VERY new to this. Commented Aug 23, 2019 at 11:23

3 Answers 3

6

You are benchmarking printf vs cout, since these are the major bottlenecks in your program.

printf is a terribly slow function, but probably still faster than osteam, which will have to maintain its own private hell of template meta programming, to keep it as flexible as required by the C++ standard. cout is definitely far more flexible and complex than printf. More features means slower code.

If you truly want to compare the two languages, drop the print functions and replace them with a dummy function "foo", with external linkage:

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

When benchmarking that code with gcc -O3 for x86, I get almost identical code for C version and C++ version.

The only notable difference is the "CRT" goo that C++ added at the end of main(). It is calling atexit and various other clean-up that C will do too, but perhaps outside the application code. Still there will always be overhead in C++, because it has to call constructs and clean-up destructors of objects with static storage duration. C doesn't have to do this.

Sign up to request clarification or add additional context in comments.

4 Comments

If you don't include iostream then the two are actually identical (aside from name mangling of foo). The key takeaway is that just including iostream contributes some (small) overhead to your program.
@MilesBudnek I'd rather suspect that including anything with static storage duration objects creates overhead.
Template meta programming does not affect execution speed. Things like buffering strategies, flushing, and synchronization do.
@aschepler All manner of overhead code affects execution speed. Things that can be resolved at compile-time don't, but meta programming almost always means overhead code. And so ostream is dreadfully slow.
2

The reason why C++ cout is slow is explained in here.

By default, iostream objects and cstdio streams are synchronized (as if this function was called with true as argument).

So by default cout is synced with stdio.

Try executing the following to speed up.

ios_base::sync_with_stdio(false) 

But be careful, this code will print something you don't expect.

#include <iostream> #include <cstdio> int main() { std::ios::sync_with_stdio(false); std::cout << "a\n"; std::printf("b\n"); std::cout << "c\n"; } 

Comments

1

Compiling

#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; } 

with basic modern optimizations (-Os) gets

$ 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 $ 

(your C version is c1, your C++ version is c2, the above C++ version is c3).

Averaging the timing for 100 runs each,

$ 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 

Used properly, C++'s iostreams are faster than C's stdio.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.