How C is not a subset of C++

compiler pedantry

Posted by eric on March 10, 2017

It is often said C is a subset of C++. I’m going to show how that isn’t strictly true.

The two following code examples look like they should be C-subset-of-C++ that will compile in C and C++, but will in fact only compile for one language. The differences in one cause compilation errors in the other language, while shared code produces different behaviors. Comments in the code explain the differences.

This will only compile in C:

/*This will compile in C but not C++*/
#include <stdlib.h>
#include <stdio.h>

/*
   C can have multiple declarations, not C++ 
*/
int test;
int test;
int test = 1;
int test;

double db;
void func() {
    struct db {
        int a;
        int b;
        int c;
        int d;
        int e;
        int f;
    };
    /*
       Size of struct in C++.
       Size of double in C.
    */
    int x = sizeof(db); /*hides double in C++*/
    printf("%d\n", x);

    /*
       Size of char in C++.
       Size of int in C.
    */
    int y = sizeof('a');
    printf("%d\n", y);

    /*
       You can call main in C, not in C++.
       Also, don't need a prototype for a
       function in C, but you do in C++.
    */
    main();
}

/*Types can be defined in return or argument types in C, not in C++*/
void print(struct X { int i;} x);

int main(void) {
    /*
       initializing an array without enough
       room for the trailing nul is an error
       in C++ but will compile in C
    */
    char b[3] = "Bob";

    /*
       typedef and struct tag names can
       have same name in C, not in C++
    */
    typedef double db;
    struct db; /*error in C++, valid C*/
    struct st {
        db x;
        double db;/*error in C++, valid C*/
    };

    /*
       Trivial, but C++ keywords that aren't used
       in C can be identifiers.
    */    
    int new = 0;

    /*
       C can have an implicit conversion from
       a void* pointer in C, C++ needs a cast
    */
    char *str = malloc(10);

    if(test) {
        test = 0;

        /*
           A function in C defined with empty params
               int f();
           can take any number of argument of any type.
           C++ takes this to mean no arguments and will
           throw a compilation error if one is passed.
        */
        func(b);
    }

    return 0;
}

This will only compile in C++:

/*This will compile in C++ but not C*/
#include <stdio.h>

/* prototype required in C++ if not defined yet */
void func(void);

int main(void) {
    /*
       C99 has variable-length arrays, but can't be initialized
    */
    const int size=4;
    char b[size] = "Bob";

    func();

    return 0;
}


double db;
void func(void) {
    struct db {
        int a;
        int b;
        int c;
        int d;
        int e;
        int f;
    };

    /*
       Size of struct in C++.
       Size of double in C
    */
    int x = sizeof(db); /*hides double in C++*/
    printf("%d\n", x);

    /*
       Size of char in C++.
       Size of int in C.
    */
    int y = sizeof('a');
    printf("%d\n", y);
}