Main image of article C++ and C: How These Languages are Diverging

C++ started life as “C with Classes back in the 1980s, though it was quickly renamed “C++.” For much of the past thirty-odd years, C++ has been regarded as a superset of C; any C program could be compiled by any C++ compiler. 

But the two languages have been slowly drifting apart. C++ didn’t change much until 2011, when a program of three yearly updates began. On the other hand, C had new versions in 1999 (C99) and 2011 (C11); there was also C18, with bug fixes and technical clarifications. 

It takes time for new compiler versions to support these changes, but C++ compiler changes are now well ahead of the game, with a considerable amount of C++ 20 already in GCC, Clang, MS VC++ and others (as this chart shows). 

Dynamic Arrays

C++ has had std::vect for a number of years; that’s how you implement dynamic arrays. There's also std::array, but that is a fixed size at compile time—it's just a wrapper around C-type arrays. C, like C++, had fixed-size arrays right from the start; the only way to get dynamically allocated arrays was by doing tricks with getmem and using pointers. 

Since C11, C has had variable-length arrays whose size is determined at runtime. Here's an example:

#include <stdio.h>

void AllocateArray(int size) {
  int data[size];
  printf("Size of data=%d\n",(int)sizeof(data));
}

int main(){
  AllocateArray(100);
  AllocateArray(500);
  AllocateArray(750);
}

When compiled with GCC, the open-source C compiler, this outputs the following:

Size of n=400
Size of n=2000
Size of n=3000

This shows that 100 ints occupies 400 bytes (as you’d expect). Note I said GCC, because when I compiled this with Visual C++, it rejected it; the declaration of the array size at runtime is invalid, same as it is with older C, because size is not a constant. 

Initializing Structs

I wrote an “Asteroids” game in C and used a small struct to hold game-level data:

struct level {
	int nums[4]; // how many of each size of asteroid
	int aliens; // how many aliens
	float factor; // from 1.0 to 1.5 - multiply asteroid speed by this
};

struct level levels[50];

So in C++, you might initialize the first two levels with this declaration:

level lvls[2] = {
	{ {0, 0, 0, 1}, 5,1.3f },
	{ {0, 0, 0, 2}, 5,1.35f }
};

C, though, has had a better initializer since C99:

struct level levels[2] = {
{ .factor = (float)1,.aliens = 1,.nums = { 0,0,3,3 } }, // Level 1
{ .factor = (float)1,.aliens = 0,.nums = { 0,1,3,3 } } } // Level 2

This is tagged initialization, and does not require the order of the data to match the order of fields in the struct, as the C++ initialization does.

You could use a C++ initializer list or a constructor to initialize the struct, as a struct and a class are the same (just with different levels of default access), but that would be even clunkier. You want to have data initialized implicitly, not needing code to do it.

The Restrict Keyword

This is an interesting case, because although it's only a C99 feature, some C++ compilers actually allow it unofficially. This type of thing is not unusual: For many years, for example, some C compilers allowed the single line comment // even though it wasn't a C feature.

The keyword restrict applies to pointers, and tells the compiler that, for the scope of the pointer, the target of the pointer will only be referenced by the pointer or copies of it. This lets the compiler perform some optimizations because the pointer isn't being aliased, and checks for what can be left out. If you do access the referenced data elsewhere, then the results are undefined. 

Auto Keyword

Both languages have had auto for a long time; it referred to a storage class. Specifically, it meant variables declared in a function. It's one of those things that nobody ever uses, so developers decided to reuse it in C++ 11 onwards as a way of declaring a variable and letting the compiler determine the type from the initial value.

If you know C#, then auto is used exactly as var in C#:

void test() {
	auto count = 0;
	auto fred = "My name";
...

Here the compiler determines ‘count’ is an int and ‘fred’ is a char *. 

You can't have auto count; by itself, it must have an initial value that provides the type. And if you want ‘fred’ to be a std::string instead of char *, add an ‘s’ to the end of the string literal, like this:

auto fred = "My name"s;

This happened because the compiler picked the simplest type that matches, so it replaces auto with char *, not std::string.

Conclusion: C++ and C, Separating Slowly

For things such as initializing data, it is possible to link C-compiled objects into a C++ object, though it seems a bit of a messy way to do it.

I compiled most examples with VC++ 2019/GCC/G++. One thing that I'd not realised is that the Visual C++ compiler only supports the minimum subset of C99 needed, not the full C99, so no restrict (for example). 

I believe the reason for this is that you can now install Clang into Visual C++, so there's no need for Microsoft to do further work on their C compiler; you can also install GCC or any other C++ compiler. 

Does it matter that C is now probably only 99 percent a subset of C++ instead of 100 percent? Probably not, but let’s see how this evolution progresses over the next few years.