The learning of programming languages usually starts with functional programming and only then moves on to object-oriented programming. Some people will stop at the functional programming stage never making it to OOP.

Even 60 years after the invention of object-oriented programming, we can still hear the question: why C++ and not C? The point is “C++ has too big an overhead.” But does the C++ overhead really make slower execution and bigger executables?

I decided to conduct my own research on C vs C++ and check if I could debunk the myth about too slow or too big C++. Let’s break down some general terms and then move on to the main question of comparing C++ to C on my own practical examples.

Differences between C and C++: introduction

The C toolbox consists of a set of quite straightforward instructions the machine has to follow. To make a program, C divides the problem into smaller modules until they can be executed as steps. This simplicity is really beneficial when the software doesn’t go beyond resolving a simple task within a predictable environment.

Things get more complicated as soon as you develop a bit more complex programs that have problems you cannot solve with just a sequence of instructions. For instance, the steps depend on circumstances or it’s too hard to predict and write instructions for each situation.

For a more complex task, it’s better to have something more than just a set of steps. Here C++ and object-oriented programming come into play. While developing more complex software, you’ll want the language to understand not just simple and precise instructions on what to do, but also some abstract notions.

With C, you will need to do all the “thinking” yourself, “translating” complicated concepts into the same set of instructions. This will result in a lot of copying and pasting of the code fragments. With the C++ language, you can talk to a machine in a more of an “adult” language, that can already contain terms like classes, objects, polymorphism, inheritance, encapsulation, etc. The higher level of abstraction allows the language to resolve more complex problems.

Now that we have a basic understanding of what the C++ vs C discussion is all about, let’s start with a bit of history and theoretical base that will help us understand the similarities and differences between the two languages.

What is C programming language?

The story of the C programming language begins in the ATT & Bell laboratory where Ken Thompson and Dennis Ritchie were working on the MULTICS project. When the project was closed, Ken Thompson started working on the Space Travel game and ended up writing a completely new Unix operating system from scratch, using the assembly language.

Dennis Ritchie joined Thompson to find a way to port Unix to other computers. They noticed how much easier it was to work with higher-level languages compared to the assembly language. After some experiments with the higher-level languages available at that time, they ended up writing a new programming language called C.

Soon other developers started adopting the new language and it led to the widespread use of C. Many modern programming languages, including C++, Python, Java, and Ruby, are based on C. That’s why C is often referred to as the ‘mother’ of programming languages.

C language still has a reputation as a low-level programming language used for developing operating systems, drivers, software for embedded devices, and other programs. C is a procedural, or structural programming language: its code consists of a quite straightforward set of instructions easily understood by machine language.

Dennis Ritchie and Ken Thompson in the Bell Laboratory, 1972.

Key features of C

Let’s mention some features of the C language.

  • Structural or procedural programming language: a C program is a linear flow of function sequences.

  • Simplicity: a quite straightforward syntax and a small set of keywords are easier to learn.

  • Modular programming: C divides a larger program into smaller pieces that are easier to manage.

  • Dynamic memory allocation: allows allocating memory during runtime instead of compile time.

  • Portability: C is a machine-independent programming language that can be written on one platform and run on another.

  • Speed: compared to other languages like Python or Java, C executes faster being a compiled language.

Major C versions

Here’s the summary of the most significant major versions of the C programming language.

  • C90 was the first standardized version, created by the American National Standards Institute — ANSI and adopted by the International Organization for Standardization — ISO.

  • C99 is the next standardized major version which has some additional features like new data types, inline functions, etc.

  • C11 is the latest as of now major version and has support for atomic operations, static assertions, and multi-threading.

And what is C++?

In the 1970s computers evolved significantly and the C language started to experience difficulties and limitations. In the 1980s Bjarne Stroutstrup created a new object-oriented language C++ that could handle the new computer capabilities.

C++ offered a different approach to programming in comparison to C: the C++ code could be abstracted and organized better using classes. Since C++ was based on C, the new language had the same efficiency level as its predecessor, but allowed for a higher level of abstraction, including classes and objects.

First, it was called ‘C with classes’ and in 1984 was renamed to C++. Basically, C++ is a superset of C plus object-oriented programming features like exception handling, templating, and a more extensive standard template library. Object-oriented programming language creates more usable and readable code with higher data security.

Key features of C++

Let’s now talk about some features of object-oriented C++.

  • Higher level of abstraction: C++ is an object-driven language and has properties like classes, objects, inheritance, polymorphism, and others not available in C.

  • Compiler-based: a compiled language is converted into machine code so the processor can execute it. It results in better performance compared to interpreted languages like Python or Java.

  • Dynamic memory allocation: the memory needed to run the program is allocated during the runtime.

  • OOP: object orientation helps make code more flexible, solve problems more efficiently and prevent data redundancy.

  • Low-level system access: since C++ is based on C, it offers the same level of access to hardware.

  • Extensible: lots of libraries and frameworks allow for the extension of the language functionality.

Major C++ versions

  • C++98: The first version standardized, published in 1998.

  • C++03: Revised in 2003, with some technical corrections and improved compatibility with C.

  • C++11: The version got some improvements and got new features like multithreading and powerful templates. Released in 2011.

  • C++14: Published in 2014 with new features like binary literals and improved compile times.

  • C++17: The version supports nested namespaces, features an improved parallel algorithm, and better handling of constexpr functions. Published in 2017.

  • C++20: The newest version of C++ as of now, released in 2020. Got new features like modules, concepts, ranges, and coroutines.

Discover C and C++ similarities

Syntax

Basic syntax is similar. C++ includes almost all operators and keywords of the C language and they do the same in both C and C++.

Grammar

Basic grammar is the same, with C++ featuring a bit more extended grammar.

Code structure

C and C++ have the same code structure.

Memory allocation

Both languages support dynamic memory allocation and they both have manual memory management.

Compilation

Both C and C++ are compiled languages making them faster than interpreted languages like Java or Python.

Memory model

In both languages, the basic memory model is close to hardware.

What is the difference between C and C++?

The main difference between C and C++ is in paradigm: while C is a function-driven language, C++ is an object-oriented programming language. This makes them totally different languages despite one being based on another. Let’s mention several other C vs C++ details. 

Programming approach

C follows a top-down approach: it takes the main problem and breaks it down into subproblems that it already can solve directly. The sub-solutions are combined to resolve the main problem. C++ follows a bottom-up approach starting from the lower-level design as a base on which it can build higher-level solutions.

Scope

C is mostly used in developing software and firmware for embedded systems or other low-level implementations. C++ is mostly used for network and server-side applications, gaming engines, photo and video editing tools, etc.

Data security

C’s main focus is on functions or procedures, so data security here isn’t a priority at all. In C++, data is the main building block of the program, so it is better secured with encapsulation, access specifiers, and classes. Encapsulation makes sure the data structures and operators are used as intended.

Focus

C as a procedural language has more emphasis on the sequence of steps to solve a problem. C++ as an object-oriented language emphasizes on objects and classes as the foundation on which the solution is built.

Compatibility with other languages

C++ is compatible with C as well as other generic programming languages. C is not compatible neither with C++ nor with other languages. It means that a program written in C will compile and run with a C++ compiler, but not vice versa.

Data types

C supports only primitive and built-in data types, while C++ supports primitive, built-in, and user-defined data types. C++ also supports Boolean and string data types.

Function overloading and overriding

C does not support either function overloading or function overriding, while C++ supports both.

Exception and error handling

C++ can handle exceptions and errors with the try-catch blocks, while in order to handle exceptions in C you will need a workaround as C doesn’t support direct exception handling.

File extension

A program built with C usually has a “.c” file extension. C++ programs have a “.cpp” file extension.

Pointers and references

C only supports pointers and doesn’t support references, while C++ supports both pointers and reference variables.

These are just several examples of C vs C++ differences in theory. Let’s now check
how the differences between C and C++ show up in practice.

Comparing C++ to C in the example: switching LEDs on Arduino using 4 approaches

I decided to write my own program for controlling LEDs using direct C, C with a function, structured C, and C++. I used the simplest first example on the Arduino, switching LEDs on and off. I wanted to control any number of LEDs with different blinking times. I programmed 4 solutions to the same problem first with 2 LEDs first, and then with 10 LEDs.

1. Direct C code

The first one — I called it “direct C code” — is an absolutely flat hierarchy. It doesn’t even define its own functions, all variables are globally defined.

#include <Arduino.h>

byte state1 = 0;
int pinnr1 = 12;
unsigned long TimeOn1 = 400;
unsigned long TimeOff1 = 500;
unsigned long NextTime1 = millis();

byte state2 = 0;
int pinnr2 = 13;
unsigned long TimeOn2 = 100;
unsigned long TimeOff2 = 300;
unsigned long NextTime2 = millis();

unsigned long loopcounter = 0;
unsigned long timerstart = 0;

void setup() {
  // put your setup code here, to run once:
  digitalWrite(pinnr1, 0);
  digitalWrite(pinnr2, 0);
  Serial.begin(9600);
  timerstart = millis();
}

void loop() {
  // put your main code here, to run repeatedly:
  if (NextTime1 < millis()) {
    if (state1 = 0) {
      digitalWrite(pinnr1, 1);
      state1 = 1;
      NextTime1 = millis() + TimeOn1;
    } else {
      digitalWrite(pinnr1, 0);
      state1 = 0;
      NextTime1 = millis() + TimeOff1;
    }
  }

  if (NextTime2 < millis()) {
    if (state1 = 0) {
      digitalWrite(pinnr2, 1);
      state2 = 1;
      NextTime2 = millis() + TimeOn2;
    } else {
      digitalWrite(pinnr2, 0);
      state2 = 0;
      NextTime2 = millis() + TimeOff2;
    }
  }
  
  if (loopcounter++>10000) {
    Serial.println(millis()-timerstart);
    timerstart = millis();
    loopcounter=0;
  }
}

2. C with a function

This second approach uses C with a function that makes the LEDs flash.

#include <Arduino.h>

void  DoLED(unsigned long *vNextTime, int vPinNr, byte *vState, unsigned long vTimeOn, unsigned long vTimeOff) {
  if (*vNextTime < millis()) {
    if (*vState = 0) {
      digitalWrite(vPinNr, 1);
      *vState = 1;
      *vNextTime = millis() + vTimeOn;
    } else {
      digitalWrite(vPinNr, 0);
      *vState = 0;
      *vNextTime = millis() + vTimeOff;
    }
  }
 
}

byte state1 = 0;
int pinnr1 = 12;
unsigned long TimeOn1 = 400;
unsigned long TimeOff1 = 500;
unsigned long NextTime1 = millis();

byte state2 = 0;
int pinnr2 = 13;
unsigned long TimeOn2 = 100;
unsigned long TimeOff2 = 300;
unsigned long NextTime2 = millis();

unsigned long loopcounter = 0;
unsigned long timerstart = 0;



void setup() {
  // put your setup code here, to run once:
  digitalWrite(pinnr1, 0);
  digitalWrite(pinnr2, 0);
  Serial.begin(9600);
  timerstart = millis();
}

void loop() {
  // put your main code here, to run repeatedly:
  
  DoLED(&NextTime1, pinnr1, &state1, TimeOn1, TimeOff1);
  DoLED(&NextTime2, pinnr2, &state2, TimeOn2, TimeOff2);
 

  if (loopcounter++>10000) {
    Serial.println(millis()-timerstart);
    timerstart = millis();
    loopcounter=0;
  }
}

3. Structured C with structures and functions

This solution uses structures for the LEDs and functions to operate them. Actually, it is object-oriented programming without using C++.

#include <Arduino.h>

struct LED {
  byte state = 0;
  int pinnr;
  unsigned long TimeOn = 500;
  unsigned long TimeOff = 500;
  unsigned long NextTime = millis();
};

void SetOn(LED vLED)
{
  vLED.state = 1;
  digitalWrite(vLED.pinnr, 1);
};
void SetOff(LED vLED)
{
  vLED.state = 0;
  digitalWrite(vLED.pinnr, 0);
};
void Check(LED vLED)
{
  if (vLED.NextTime < millis()) {
    if (vLED.state = 0) {
      SetOn(vLED);
      vLED.NextTime = millis() + vLED.TimeOn;
    } else {
      SetOff(vLED);
      vLED.NextTime = millis() + vLED.TimeOff;
    }
  }
};

void SetLED(LED vLED, int vPin, byte vState, int vTimeOn, int vTimeOff)
{
  vLED.state = vState;
  vLED.pinnr = vPin;
  vLED.TimeOn = vTimeOn;
  vLED.TimeOff = vTimeOff;
  vLED.NextTime = millis();
  pinMode(vLED.pinnr, OUTPUT);
};


LED L1;
LED L2;

unsigned long loopcounter = 0;
unsigned long timerstart = 0;

void setup() {
  // put your setup code here, to run once:
  SetLED(L1, 12, 0, 400, 500);
  SetLED(L2, 13, 0, 100, 300);

  SetOff(L1);
  SetOff(L2);

  Serial.begin(9600);
  timerstart = millis();
}

void loop() {
  // put your main code here, to run repeatedly:
  Check(L1);
  Check(L2);
  
  if (loopcounter++>10000) {
    Serial.println(millis()-timerstart);
    timerstart = millis();
    loopcounter=0;
  }
}

4. Object-oriented programming using C++

Finally, the “true” object-oriented solution is written in C++.

#include <Arduino.h>

class LED {
  public:
    byte state = 0;
    int pinnr;
    unsigned long TimeOn = 500;
    unsigned long TimeOff = 500;
    unsigned long NextTime = millis();
    void SetOn()
    {
      state = 1;
      digitalWrite(pinnr, 1);
    };
    void SetOff()
    {
      state = 0;
      digitalWrite(pinnr, 0);
    };
    void Check()
    {
      if (NextTime < millis()) {
        if (state = 0) {
          SetOn();
          NextTime = millis() + TimeOn;
        } else {
          SetOff();
          NextTime = millis() + TimeOff;
        }
      }
    }

    LED(int vPin, byte vState, int vTimeOn, int vTimeOff)
    {
      state = vState;
      pinnr = vPin;
      TimeOn = vTimeOn;
      TimeOff = vTimeOff;
      NextTime = millis();
      pinMode(pinnr, OUTPUT);
    };
};

LED L1(12, 0, 400, 500);
LED L2(13, 0, 100, 300);

unsigned long loopcounter = 0;
unsigned long timerstart = 0;

void setup() {
  // put your setup code here, to run once:
  L1.SetOff();
  L2.SetOff();
  Serial.begin(9600);
}

void loop() {
  // put your main code here, to run repeatedly:
  L1.Check();  
  L2.Check();

  if (10000<loopcounter++) {
    Serial.println(millis()-timerstart);
    timerstart = millis();
    loopcounter=0;
  }
}

Approaches 3 and 4 are very similar. This is also reflected in the size of the code and the memory used. The smallest code is the direct C code with 2198 bytes, followed by the C code with 2214 bytes, and finally the C++ code with 2444 bytes. This means that the object-oriented solution with C++ produces a .exe file that is only about 4% larger than the C .exe file.

Then I decided to scale it and write solutions for 10 LEDs to flash. Not surprisingly, both versions suddenly produced the same size programs. Consequently, as the programs get more complicated, the code difference between C and C++ gets smaller. Not to mention the source code, which swells twice as much in functional programming, i.e. functional programs produce more unreadable source code. Check out the tables below.

Solution with 2 LEDs

Direct CFunctional CC with StructuresC++
Source code in bytes1139113312161181
100%-1%7%4%
exe Code in bytes2198221423182444
100%1%5%11%
Stack size in bytes of 8192204226226226
Time for 10’000 cycles in msec636315563
Comparison of the code size and speed of the C and C++ solutions for 2 LEDs

Solution with 10 LEDs

Direct CFunctional CC with StructuresC++
Source code in bytes3937277017201576
100%-30%-56%-60%
exe Code in bytes2632262631822604
100%-0%21%-1%
Stack size in bytes of 8192200246346286
Time for 10’000 cycles in msec2307511304449
Comparison of the code size and speed of the C and C++ solutions for 10 LEDs

So what to choose: C or C++?

What’s the conclusion? Despite the C++ overhead, the experiment shows that the much more readable and maintainable object-oriented code in C++ is the better solution in any case.
I have not even considered the influence of inheritance and tons of benefits associated with it. My answer to the question of what to choose C or C++ would always be C++ for its maintainability.

Another thing worth mentioning is the worst of all solutions was to try to recreate the object orientation with structures and associated functions. It proves that in some cases, choosing C for its simplicity complicates things even worse.

The discussion “Which is better, C or C++” is probably not quite correct and makes the question too reductive. C++ is more versatile but has a steeper learning curve, while C may be more beginner-friendly but is not an optimal choice for complex projects.

My appeal to all teachers is not to stop with functional programming. Instead, continue with practical examples of object-oriented programming that show the benefits of C++ in particular and OOP in general.

A few words from the author

I believe writing good software is not just a job, it’s a craft, even a kind of art. I started studying at the dawn of the computer era at Electronic Engineering at the ETH in Zürich. The University was just about to open a dedicated computer science department.

At that time there was still a lot of assembler programming. CPUs were slow, memory limited. Code had to be optimized to the extent. During our studies a lot of programming languages besides Pascal were thrown at us: C, Ada, Lisp, Basic, Cobol, Fortran, AXL, and later C++.

After my studies, I worked for different companies learning to combine theory with practice. Later I led bigger teams to build even bigger machines and systems. In those 30 years of experience, I got a strong feeling of what works and what doesn’t. Or what is hype and what is not. In my articles, I would like to pass on some of the few things I consider very practical and which can save other engineers’ time.

Frequently asked questions on C and C++

Which language is faster C or C++?

Generally, C is faster than C++ due to the overhead from object-oriented programming features like virtual functions or exception handling.

Why use C++ instead of C?

True benefits of C++ are discovered while developing complex software requiring a higher level of abstraction in the programming language.

Is C++ a good starting language?

C++ has quite a steep learning curve and may seem difficult for beginners without a background in general computer programming. It’s a good starting point for learners with some background knowledge willing to master object-oriented programming.