(Note: this is not a rant, but I am going to rant during the short preface. Sorry.)

Preface

Ok, relax. Take a deep breath. Now, listen to (read) me: there is no such language as C/C++. There is C, there are C++s and they are all different languages.

You may know one of them, you may know all of them, but saying you know “C/C++” just doesn’t make any sense.
Would you ever write in your résumé that you know, e.g., “C/Objective-C”? Or “Java/Kotlin”? If your answer is “of course not, they are different languages!”, such an answer is correct and you should stop writing “C/C++”. Put a damn comma between two different languages.

Hold on, I can sense some of you saying:

But in my case it makes sense because…

The general answer is that it would also make sense to write “C, C++”. Maybe in your very own case it makes sense…I will address that in the appendix of this article. Please, bear with me until the end.

Why this article

It happened countless times that I saw resumes, curricula, presentation pages and whatnot saying that a person knows “C/C++”. I can’t state for every one of them, but the people I had to deal with in real life, either knew a decent C and a little bit of C++98 or they knew C++98 (maybe C++11) and they were sure they could write C code with little-to-no adjustments.

The former were not C++ developers. The latter were not C developers.
It is not a crime to not know a language or to know just a little bit of it. But you should at least know what you know and what you do not know.

What does it have to do with videogames?

Some of the most widespread programming languages in the videogame industry are C++s. It will help to know at least the main differences and how to distinguish between C and C++s.

I will not cover here such differences (not now!), but at least you will know that they exists.

Why are you repeating C++s?

I will explain that.

Is every C code valid C++ code?

Ok, here is a very simple snippet:

int bar(int* arr, const int size);

int foo(const int size) {
    int arr[size];
    for(int i = 0; i < size; i++) arr[i] = 0;
    return bar(arr, size);
}

We do not care about what bar() does, just concentrate on foo(). Here are two questions:

  1. Is this valid C code?
  2. Is this valid C++ code?

If you answered anything but:

  1. It depends.
  2. It depends.

…you were wrong.


Let us say that we want to be pedantic, i.e. strictly following the ISO specifications. You can just add -pedantic to any compiler (but MSVC, more on that later).
The answer are now:

  1. It still depends
  2. No

Did you get them right? No and you do not even believe me? Here you are:

Using the latest gcc and building with -pedantic -Werror…VLAs (Variable-Length Arrays) are just not valid ISO C++ code. In another words, if you declare a C-style array in C++, its size must be known at compile time, you cannot use a variable.

Ok, but this is valid C code, right? Well…

…it is not always the case. If you are stuck with C90 you are out of luck, VLAs are not valid C90 code. Actually, GCC will allow you to do that if you are not -pedantic, but you are out of luck if you are using MSVC, no VLAs allowed whatsoever, neither in C nor in C++.

But…what are VLAs? They are just variable-length arrays (sic!) allocated on the stack. Have you ever heard about alloca()? Unless you had to deal with some reasonably-big ANSI C code (not school assignments), probably not, and for a good reason.

alloca is just like malloc, but on the stack! Nice, now we can simulate VLAs in plain old C90, right…?

…uh‽‽‽

Well, if you are accustomed to MSVC (in C++ mode) or to C99 code, or you just thought that knowing C++ code was enough to write C code…here we are.

In C90 you could not declare variables inside a loop declaration. And that is not all, you are only allowed to declare variables at the very beginning of a block. Every declaration must happen before any statement.

This is not a valid C90 snippet either:

{
    int i = 0;
    foo(i);
    int j = 1
    bar(j);
}

Because we declared j after the statement foo(i).

Now, here is the cursed code adjusted for C90:

Confused? Well, that’s for a good reason. Maybe you think that C90 is old and deprecated…well, in 2015 I had to work with C90 code written in that very year. We soon migrated to C99…but still I had to deal with it for a while. And it was meant to be run on a standard and recente x86-64 platform. Just a PC.

NOTE: if we want to be really pedantic, in C11 VLAs are optional, not mandatory. But I did not manage to find any C11 compiler not supporting them. We were lucky this time.

Dive into the differences

All right! I will just write in my CV that I know “C, C++” and I will be fine.

Well…no. Not yet.

C

Here is another question for you:

  1. Does C support function overload?

And the answer, again, is:

  1. It depends.

First of all, clang has __attribute__((overloadable)). GCC on the other side, does not have such a wonderful attribute.

But we were -pedantic right?

  1. Does ISO C support function overload?

Of course…

  1. It depends.

Have you ever heard of _Generic selection? Are you familiar with such syntax?

#define foo(val) _Generic((val),      \
                           int: foo_i, \
                          char: foo_c,  \
                        double: foo_d    )(val)

If not, you do not know C11. (And of course, this is not valid C++ code, no matter how many flags you set.)

Now, if we stay in the realm of C, which is such a slow-changing language, if you just write that you know “C” is ok. Maybe you are not familiar with C11 features, but since the only new syntax you should learn is the _Generic one…you can adjust pretty quickly. If you are an experienced C99 developer and I want to hire someone for my C11 project, you are pretty much as valuable as a C11 developer with the same experience.

C++

Ok, maybe you are a decently-experienced C developer, and during a college course you learned about classes, objects and used them with a C++ compiler (maybe Dev-C++!).

You know what a class and a method are. But since your C++ course, you moved into Java, C#, or something else “higher level”. And since you know about OOP, you know C and you worked with C++ in the past, you write that “C++” entry in your CV.

If someone read that CV, they would immediately know that you do not know C++ and that maybe you know a little bit of C++98 mixed with C. Or, if lucky enough, a little bit of C++11.

Do you remember that I kept writing C++s instead of just C++? Now you will understand why.

Here is a list of some features available as of C++20, without any specific order (count how many of them you know):

  • Classes and objects
  • Templates
  • constexpr
  • consteval
  • Static assertions
  • Lambdas
  • Templated lambdas
  • Fold expressions
  • Concepts
  • Non-type template parameters
  • Smart pointers
  • std::variant
  • Structured binding
  • auto (not the automatic storage keyword)

How was your score? If it was less than 8, you probably do not even fully know C++11.

Now, you may think that I am being overly pedantic, that you can move from a version to the other without a little bit of effort.

While that is true, it is true for any language. And if I need to hire someone already experienced with C++17, your knowledge of a subset of C++98 is by no means enough. Because nowaday, C++ code can look like:

template<typename T>
concept Meowable = requires(T a) { a.meow(); };

template<Meowable ...Args>
consteval int meow_count(Args&&... args) {
    return (args.meow() + ...);
}

struct Cat { constexpr int meow() { return 1; } };

int foo() {
    return meow_count(Cat{}, Cat{}, Cat{}, Cat{});
}

And such a snippet will generate only four (4) line of assembly, only for the foo() function, and it will return just 4, without any run-time calculation. Everything is done at compile-time. Without any optimization activated. It is all compile-time by standard, every compiler must generate such assembly.

Here it is, built with gcc 10.1, with -std=c++20 -fconcepts -O0 -pedantic -Werror

That is not anything remotely similar to what a C++ developer could have seen in the ’90s. It’s a whole different monstrosity, whether it is a good or a bad thing.

To be honest, that does not look anything like C++14 code either.

Postface

I hope that you now understand how much difference there is between C and C++ and between C++ versions.

Of course, it is not necessary to write every single version of the language in your CV. It is reasonable e.g. to say you know C++11/14 or C++17/20.

And it is perfectly fine to say that you just know C++98 because you attended that OOP crash course during college. If you are versed in other languages and experienced overall developer, you could be an equally valuable C++20 developer with a little bit of effort.

But it is also important to state what you know and to know what you do not know (how many time did I say the word “know” until now?). Because not only is difficult go up to the newest versions of C++, but it is also difficult to go down to the oldest ones.

If I ever found myself stuck with an old compiler limited to C++98, I would just switch to C. Not because C++98 is a bad language, but because I work mainly with C (for a living) and C++17/20 (in my side projects). And I honestly do not know what would my toolset be in C++98. Do I have non-type template parameters? What parts of STL are available? Smart pointers are not present…can I use boost for them? Delegate constructors are not available…right?

In the end, just a suggestion: if you need to learn C++ in order to enter the gamedev scene, learn a modern C++ and jump right into C++17, at least. Even C++20 given that it a complete standard and all the major compilers’ support is reaching the final stages.

Here some C++17-ready game engines:

Want some open-source stuff? We’ve got you covered!

  • OpenRCT2 requires C++17!
  • Halley is another very interesting engine built upon C++17.
  • EnTT requires C++17 too. Well, there is the cpp14 tag, but last commit was Sep 2, 2018.

TL;DR

Please, just stop writing “C/C++” and state which C++ version you know.

Appendix: mixing C and C++

Maybe you use a lot extern "C" {} and mix together C and C++ code for whatever reason. Embedded programming, dealing with old libraries…

Maybe you are really specialized in mixing together C and C++, which is not something anyone can do.

In you case “C/C++” would be actually the right thing to write. But we all know that it is not what the vast majority of people intend. Sadly, since the abuse of such notation, it is a better idea to write something more creative (and verbose):

Programming languages: C, C++14, C/C++ interface

Here you are.