Much is misunderstood about the similarities between C and C++. While C++ began as a superset of contemporaneous C, both languages have moved on. Just as we are not simply supersets of one or both of our parents.
There are specific cases where it is possible to create a source file that can be compiled as either C or C++ and, using the same compiler with the same compile flags, produce the same executable object with the same instructions.
Empirically, these have the same performance.
For much of the mutual lifespan of the two languages, C was typically the fastest, supra-assembly, language for many scenarios because it was most capable of a 1:1 statement:instruction coding.
- a = 1; // maps to arm: `mov w20, 1`
Unfortunately, the majority of today’s architectures are highly complex with multiple tiers of cache, speculative execution, predictors, and deep pipelining.
Assuming you are using a modern compiler on modern architecture – clang, gcc, msvc; x86_64, arm64, amd64, m1 – then the C and C++ compilations will share a huge number of codepaths and features.
Early C++ – that is the features distinct from C such as class methods etc – often suffered runtime performance overheads.
- // C implementation
- void execute(int (*op)(int, int), int l, int r, int* out)
- if (op) *out = op(l, r);
- // C++ implementation
- struct S
- virtual int operator()(int l, int r);
- void execute(S* op, int l, int r, int& out)
- if (op) out = op->operator(l, r);
In the C implementation, the way we use ‘op’ may make it quite obvious it will have no more overhead than a regular function call.
The C++ implementation tho is not so clear, and older C++ compilers would indeed have had to do an indirection: