GCC: Incompatibilities between C and C++

Tags: / c cpp /

About features that work differently in C and C++ for GCC compilers..

From my old blog.


Works in C but not C++

Constant variable initialisation

#include<stdio.h>
int main()
{
    const int a;
    //const int a=10;
}

The above code will compile successfully as a C program, but will give the following error when run as a C++ program.

main.c:4:19: error: uninitialized const ‘a’ [-fpermissive]
        const int a;
            ^

This is because in C, we need not give the value of the constant variable while declaring it (though it seems that we won't be able to give a value to it later as well since it is a constant. If that's the case, one wonders what's the point of making such declarations in the first place).

But in C++, a constant variable needs to be initialized when it is declared.

Typedef names

#include<stdio.h>

typedef int n;

struct n
{
    n a; //Here, n is the typedef-ed name of int
    struct n* link; //Here, n is the structure.
};

int main()
{
    printf("\n%d", sizeof(n)); //Prints 4 = sizeof(int) in C
    printf("\n%d", sizeof(struct n)); //Prints 8 = sizeof(int) + sizeof(struct n) in C
    return 0;
}

This will run all right as C.

And gives this error in C++:

main.c:5:12: error: using typedef-name ‘n’ after ‘struct’
    struct n
        ^
main.c:3:17: note: ‘n’ has a previous declaration here
    typedef int n;
            ^

C++ treats the name of struct, union, enum, etc (the type tag) as implicit typedef names.

But in C, we MUST use the struct keyword before the name of the structure when declaring its variables.

The above program, when treated as C++, first int is given an alias name of 'n'. Then we define a structure of the same name 'n'. Since C++ considers the structure name alone ('n') implicitly a typedef name of that structure, we get an error like "using typedef-name 'n' after struct".

But in C, no such implicit typedef-ing is done and an alias name same as that of a structure (or union or enum) can be made using typedef keyword.

So in C, while declaring a structure variable, the type of the variable is the name of the structure preceded by the struct keyword. Eg: struct n variable;

In C++, the struct is optional (but there are exceptions: "a notorious example where even C++ needs the struct keyword is POSIX' stat system call").

Eg:

n variable;

But

n variable;
struct n variable;

is also valid.

void pointer assignments

In C, a pointer of type void is automatically cast into the target pointer type when assigned to a pointer of any other type. So no explicit type-casting is required.

Whereas in C++, an explicit type-cast is required when a void pointer is assigned to pointer of another type.

The malloc() function returns a void pointer if it was successful. So,

int *a = malloc( sizeof(int) );

would be all right in C.

But not in C++, it would give an error like:

/home/famubu/main.c: In function ‘int main()’:
/home/famubu/main.c:5:20: error: invalid conversion from ‘void*’ to ‘int*’
    int *a = malloc(sizeof(int));
        ~~~~~~^~~~~~~~~~~~~

We can add an explicit type cast to fix this.

/home/famubu/main.c: In function ‘int main()’:
int *a = (int *) malloc( sizeof(int) );

Still, both C and C++ allow a pointer of any data type to be assigned to a pointer of type void.

Eg:

int a = 3;
int *int_ptr = &a;

void *void_ptr = int_ptr;  // Legal in both C and C++

int_ptr = void_ptr;        // Legal in C but not in C++

K&R style function definitions

Before C came to standardised,

This is known as the K&R style function definitions (or non-prototyped function definitions).

This syntax was used in the first edition of the K&R C book.

Though this syntax is now considered obsolete, gcc (and clang) would still accept it when used in a C program. But not for C++ programs.

Consider this program:

#include<stdio.h>

int main()
{
    fn(3,2);
}

void fn(a, b)
int a;  // This is optional
int b;  // This is optional
{
    printf("a: %d, b: %d\n", a, b);
}

It works fine as a C program but gives an error when compiled as C++.

I had heard of the old-style syntax but didn't know it would still work until reading an article. As the teacher who taught me C said, "gcc compiler is backward compatible with K&R C".

C++ doesn't allow this style and the function definition must be prototyped.

The above function may be re-written as:

#include<stdio.h>

void fn(int a, int b)
{
    printf("a: %d, b: %d\n", a, b);
}

int main()
{
    fn(3,2);
}

Crossing an initialisation

#include<stdio.h>
int main()
{
    switch(1)
    {
    int i = 3;
    case 1:
    printf("\n%d", i);

    }
    return 0;
}

This is valid C but invalid C++.

When compiled as C, it would print some garbage value that was in the variable 'i'.

In C++, it wouldn't compile and would give an error like

error: crosses initialisation of 'int i'

This is because in C++, a goto or switch cannot cross a variable initialisation.

Hence the following is also valid C but invalid C++:

#include<stdio.h>
int main()
{
goto label;
    int i=3;
    label:
    return 0;
}

When goto label; is encountered, the int i=3; which is an initialisation is skipped. GCC C++ compiler prohibits crossing an initialisation.

Function arguments

In C, if fn() is a function, the difference between the following functions

int fn1()
int fn2(void)

is that the first function takes an unspecified number of arguments. Meaning, it can receive any number of arguments (including zero arguments). But it seems that there is no way to access these arguments in this case.

The second function takes no arguments. So it would be an error to pass arguments to it.

ie,

fn1();
fn1(2);
fn1(2, 2.0, 'c');

are all valid function invocations but

fn2(2);
fn(2, 2.0, 'c');

are both wrong.

fn2();

is the correct way of invoking the second function.

But in C++,

int fn();

means that that the function takes no arguments

ie, it is same as

int fn(void);

Therefore, if we try to call function fn() with arguments, it would generate error like "too many arguments".

#include<stdio.h>
void fn()
{
    printf("\nHello world");
}
int main()
{
    fn(2);
    return 0;
}

Hence, this program would work fine in C but not C++.

Enumerator value

In C, enum seems to have been almost meaningless as a variable of type enum could be assigned any value without it being an error as in the following program.

#include<stdio.h>
int main()
{
    enum Dir { UP, DOWN};
    enum Dir d = 1; //No error in C. Error in C++
    return 0;
}

But C++ enum is more meaningful. Only the values specified in the declaration can be assigned. Following would work in C++:

#include<stdio.h>
int main()
{
    enum Dir { UP, DOWN};
    enum Dir d = (enum Dir) 1; //Valid C and C++
    return 0;
}

String 'overflow'

#include<stdio.h>
int main()
{
    char arr[5]="Hello";
}

Here, the size of the character array arr is only 5 but the string with which it is initialised needs 6 bytes (one extra for NUL character). So if we try to print arr, the output is likely to have some characters after the 'Hello' but still C compiler will not complain about it.

In C++, on the other hand, the program wouldn't even compile. Would get an error like:

error: initialiser string for array of chars is too long [-fpermissive]

Anonymous structures

#include<stdio.h>
int main()
{
    union u
    {
    int a;
    struct //anonymous structure. Anonymous structure and nameless structure ARE DIFFERENT!
    {
        char b[4];
    };
    };
    return 0;
}

Anonymous structures are valid in C but not C++. The above program works in C but not C++.

Compound literals

Compound literals are "literals having types other than primitive types (eg: array types)". In C, it is possible to specify compound literals in constant expressions.

#include<stdio.h>
int foo(int *a)
{
    printf("\n%d", a[2]);
}
int main()
{
    foo( (int []) {3,2,4} ); // An array literal
}

But C++ does not allow this and would give an error like "taking address of temporary array".

Works in C++ but not C

Default arguments

C++ functions can have default arguments but not C functions.

Hence following is valid C++ but invalid C.

#include<stdio.h>
int fn(int a, int b=4) //default argument
{
}
int main()
{
    fn(3);
    return 0;
}

Variadic function prototype

Prototype of variadic functions in C must have at least one specified argument followed by a comma and an ellipsis to denote undefined number of arguments like this:

void fn(int n, …);

In C++, the prototype of a variadic function need not have even a single specified argument. Just the ellipsis would do.

void fn(…);

Hence,

#include<stdio.h>
int fn(...);
int main()
{
}

Gives error like "ISO C requires a named argument before …" when compiled as a C program but works fine as a C++ program.

Also, the comma is important in C function prototypes like:

void fn(int n, …); //Valid C, valid C++

But in C++, the comma is optional:

void fn(int n …); //Invalid C, valid C++

The second case would give the following error when compiled as C:

error: expected ';', ',' or ')' before '...' token

bool keyword

The bool keyword is not present in C89. But was added in C99 in the form of _Bool with bool as a macro for _Bool.

But in C++, bool is a built-in data type.

Consider the following

#include<stdio.h>
//#include<stdbool.h>  //If this is included, will compile as C program as well
int main()
{
    bool b;
}

This program will compile as a C++ program but not as C.

To use bool of C99, we may include the stdbool header file and then it will compile as C as well.

'Constructor' and 'destructor' for a structure

#include<stdio.h>

//Works in C++
struct n
{
    n()
    {
    printf("\nHello");
    }
    ~n()
    {
    printf("\nBye");
    }
};
int main()
{
    struct n a;
    n b;
}

'Constructor' and 'destructor' for a structure is valid C++ but invalid C. These 'constructors' & 'destructors' behave like that of a class. The 'constructor' is automatically called whenever a structure variable of this structure is created and the 'destructor' is automatically invoked whenever a structure variable of this structure runs out of scope.

For example, in the above program, two structure variables of type 'n' are declared. Hence, the 'constructor' gets called twice and "Hello" is printed two times as output due to the 'constructor' and "Bye" is printed twice because of the 'destructor'.

As per Wikipedia:C++ classes (accessed around 2017. Contents might have changed now),

In C++, a structure is a class defined with the struct keyword. Its members and base classes are public by default. A class defined with class keyword has private members and base classes by default. This is the only difference between structs and classes in C++.

Eg: the following structure and class are functionally equivalent in C++.

struct name
{
    char c;
    int a;
};

class name
{
public:
    char c;
    int a;
};

structs in C++ can even have member functions.

Different output in C and C++

Result of a Boolean expression

#include<stdio.h>
int main()
{
    printf("\n%d", sizeof(1==1));
    return 0;
}

This would print 4 as a C program and 1 as a C++ program.

1==1 is a Boolean expression. C doesn't have a separate data type to store Boolean values (though C99 added this with _Bool. The header file stdbool.h also provides bool as an alias for _Bool along with macros true and false. Any assignment other than 0 or 1 to a variable of type _Bool is stored as 1).

Hence the resultant value, which is 1, is considered to be an integer. In gcc, the size of int is 4 bytes and hence the output.

But C++ has a separate Boolean data type, the result of a Boolean expression is a value of type bool. The size of bool is 1 byte. So the output of the above program when run as a C++ program is 1.

Structure with no members

It seems that syntax of C forbids an empty structure. But gcc allows this as an extension.

As gcc docs says,

> GCC permits a C structure with no members. The structure struct empty { }; has size zero. In C++, empty structures are part of the language. G++ treats empty structures as if they had a single member of type char."

So in gcc at least, the following program gives output 0 in C and 1 in C++.

#include<stdio.h>
struct n
{
};
int main()
{
    printf("\n%d", sizeof(struct n)); // Prints 0 in C and 1 in C++
}

Size of a character literal

This I got from this blog.

#include<stdio.h>
int main()
{
    printf("\n%d", sizeof('a'));
}

This prints 4 in C as 'a' is treated as an int whereas in C++ the output is 1 since it is treated as a char.

References