133

I read in a lot of books that C is a subset of C++.

Some books say that C is a subset of C++, except for the little details.

What are some cases when code will compile in C, but not C++?

MD XF
  • 7,860
  • 7
  • 40
  • 71
n00ki3
  • 14,529
  • 18
  • 56
  • 65

11 Answers11

146

If you compare C89 with C++ then here are a couple of things

No tentative definitions in C++

int n;
int n; // ill-formed: n already defined

int[] and int[N] not compatible (no compatible types in C++)

int a[1];
int (*ap)[] = &a; // ill-formed: a does not have type int[]

No K&R function definition style

int b(a) int a; { } // ill-formed: grammar error

Nested struct has class-scope in C++

struct A { struct B { int a; } b; int c; };
struct B b; // ill-formed: b has incomplete type (*not* A::B)

No default int

auto a; // ill-formed: type-specifier missing

C99 adds a whole lot of other cases

No special handling of declaration specifiers in array dimensions of parameters

// ill-formed: invalid syntax
void f(int p[static 100]) { }

No variable length arrays

// ill-formed: n is not a constant expression
int n = 1;
int an[n];

No flexible array member

// ill-formed: fam has incomplete type
struct A { int a; int fam[]; }; 

No restrict qualifier for helping aliasing analysis

// ill-formed: two names for one parameter?
void copy(int *restrict src, int *restrict dst);
Johannes Schaub - litb
  • 496,577
  • 130
  • 894
  • 1,212
56

In C, sizeof('a') is equal to sizeof(int).

In C++, sizeof('a') is equal to sizeof(char).

Sinan Ünür
  • 116,958
  • 15
  • 196
  • 339
Naveen
  • 74,600
  • 47
  • 176
  • 233
  • 60
    That can be simpified to: In C, `'a'` is an `int`. In C++, `'a'` is a `char`. – pmg Sep 23 '10 at 10:32
45

C++ has new keywords as well. The following is valid C code but won't compile under C++:

int class = 1;
int private = 2;
int public = 3;
int virtual = 4;
Graeme Perrow
  • 56,086
  • 21
  • 82
  • 121
25

There are plenty of things. Just a simple example (it should be enough to prove C is not a proper subset of C++):

int* test = malloc(100 * sizeof(int));

should compile in C but not in C++.

Mehrdad Afshari
  • 414,610
  • 91
  • 852
  • 789
  • 3
    C++ should require an explicit cast to `int*`. – Mehrdad Afshari Jul 29 '09 at 16:51
  • 11
    Long answer: malloc returns `void *`, which in C can be assigned to any pointer type, and C++ cannot be assigned to any other pointer type. – Daniel Earwicker Jul 29 '09 at 16:58
  • 5
    Imagist: a C compiler, as defined by ANSI C89 standard, shouldn't complain. – Mehrdad Afshari Jul 29 '09 at 17:08
  • 8
    It's legal C. The cast is unnecessary, possible to get wrong, and covers up a failure to include . I consider Mehrdad's statement to be the right way to write it in C. – David Thornley Jul 29 '09 at 17:18
  • 19
    @Imagist: I usually hear the opposite from C programmers. They consider it poor style to add the cast, as it may conceal bugs. Good C code does *not* use the cast. – jalf Jul 29 '09 at 17:21
  • 2
    @jalf: I consider using implicit function declarations to be poor style, and I strongly encourage always compiling with -Wall -Werror (GCC). This prevents the case where a cast here would mask a failure to include . If there's any chance whatsoever the code might get compiled as C++, it's better to do the cast. – Adam Rosenfield Jul 29 '09 at 17:41
  • 1
    @Adam: If there's any chance that the code might get compiled as C++, it's arguably better to remove the cast. Most C++ compilers will compile C as well, and I'd rather know if a compiler is compiling C as if it were C++. – David Thornley Jul 29 '09 at 17:51
  • Prior to C89, malloc() and calloc() returned char*, so an explicit cast was necessary if the target pointer was of a different type. But if you're working with a compiler *that* old, you have bigger problems AFAIC. – John Bode Jul 29 '09 at 18:30
  • @jalf: Hang out on comp.lang.c and you'll see religious debates about it on a fairly regular basis. Apparently, this is as big a deal as using EMACS over Vim. – greyfade Jul 29 '09 at 21:12
  • There is a question all about there here: https://stackoverflow.com/questions/605845/do-i-cast-the-result-of-malloc – Jerry Jeremiah Sep 08 '21 at 22:01
19

In C++, if you declare a struct, union, or enum, its name is immediately accessible without any qualifiers:

struct foo { ... };
foo x; // declare variable

In C, this won't work, because types thus declared live in their own distinct namespaces. Thus, you have to write:

struct foo { ... };
struct foo x; // declare variable

Notice the presence of struct there on the second line. You have to do the same for union and enum (using their respective keywords), or use the typedef trick:

typedef struct { ... } foo;
foo x; // declare variable

Consequently, you can have several types of different kinds named the same in C, since you can disambiguate:

struct foo { ... };
typedef enum { ... } foo;

struct foo x;
foo y;

In C++, however, while you can prefix a struct name with keyword struct whenever you reference it, the namespaces are merged, and so the above C snippet isn't valid. On the other hand, C++ specifically makes an exception to allow a type and a typedef for that type to have the same name (obviously with no effect), to allow the use of typedef trick unchanged from C.

Pavel Minaev
  • 99,783
  • 25
  • 219
  • 289
  • 1
    Your last example is invalid C: The three tags (`struct`, `union` and `enum`) share the same namespace. A better example would be `struct foo { ... }; typedef enum { ... } foo;` – schot Sep 23 '10 at 13:06
  • @schot: you're of course right, thank you for the correction. Updated. – Pavel Minaev Sep 23 '10 at 21:15
  • `typedef struct foo *foo;` is another good example: if you have a C header file with this line, you cannot `#include` it in a C++ file and still compile as C++ code (e.g. clang++ reports "`error: typedef redefinition with different types ('struct foo *' vs 'foo')`"). This can specifically cause problems linking C++ code with C code that does not follow C++'s implicit `typedef struct foo foo;` convention. – hbw Jan 23 '21 at 08:23
14

This also depends on what variety of C you're using. Stroustrup made C++ as compatible as he could, and no more compatible, with the 1989 ANSI and 1990 ISO standards, and the 1995 version changed nothing. The C committee went in a somewhat different direction with the 1999 standard, and the C++ committee has changed the next C++ standard (probably out next year or so) to conform with some of the changes.

Stroustrup lists incompatibilities with C90/C95 in Appendix B.2 of "The C++ Programming Language", Special Edition (which is 3rd edition with some added material):

'a' is an int in C, a char in C++.

The sizeof an enum is int in C, not necessarily in C++.

C++ has // comments to end of line, C doesn't (although it's a common extension).

In C++, a struct foo { definition puts foo into the global namespace, while in C it would have to be referred to as struct foo. This allows a struct definition to shadow a name in an outer scope, and has a few other consequences. Also, C allows larger scope for struct definitions, and allows them in return type and argument type declarations.

C++ is fussier about types in general. It won't allow an integer to be assigned to an enum, and void * objects cannot be assigned to other pointer types without a cast. In C, it's possible to provide an overlarge initializer (char name[5] = "David" where C will discard the trailing null character).

C89 allowed implicit int in many contexts, and C++ doesn't. This means that all functions must be declared in C++, while in C89 it was often possible to get by with assuming int for everything applicable in the function declaration.

In C, it's possible to jump from outside a block to inside using a labeled statement. In C++, this isn't allowed if it skips an initialization.

C is more liberal in external linkage. In C, a global const variable is implicitly extern, and that's not true in C++. C allows a global data object to be declared several times without an extern, but that's not true in C++.

Many C++ keywords are not keywords in C, or are #defined in standard C headers.

There are also some older features of C that aren't considered good style any more. In C, you can declare a function with the argument definitions after the list of arguments. In C, a declaration like int foo() means that foo() can take any number of any type of arguments, while in C++ it's equivalent to int foo(void).

That seems to cover everything from Stroustrup.

David Thornley
  • 56,304
  • 9
  • 91
  • 158
  • Let's not forget the fact that, in C, you must declare variables at the beginning of a scope (i.e., immediately after an opening brace), whereas, C++ allows variable declarations anywhere. – RobH Jul 29 '09 at 21:53
  • 5
    However, that's something C++ can do that C can't. I think we're looking at things you can do in C but not C++. – David Thornley Jul 29 '09 at 22:00
  • 2
    @RobH: That's true for C89 but not for C99. – jamesdlin Sep 23 '10 at 10:08
10

If you use gcc, you can use the warning -Wc++-compat to give you warnings about C code which is dubious in C++ in some way. Its currently used in gcc itself, and its gotten a lot better recently (maybe try a nightly version to get the best you can).

(This doesn't strictly answer the question, but folk might like it).

Paul Biggar
  • 27,579
  • 21
  • 99
  • 152
5
#include <stdio.h>

int new (int n) {
    return n/2;
}

int main(void) {
    printf("%d\n", new(10));
    return 0;
}

See also the C++ FAQ entry.

Sinan Ünür
  • 116,958
  • 15
  • 196
  • 339
5

The single biggest difference I think is that this is a valid C source file:

int main()
{
    foo();
}

Note that I haven't declared foo anywhere.

Aside from language differences, C++ also makes some changes to the library that it inherited from C, e.g. some functions return const char * instead of char *.

Daniel Earwicker
  • 114,894
  • 38
  • 205
  • 284
3

A number of the answers here cover syntax differences that would cause C++ compilers to fail on C89 (or C99) source code. However, there are some subtle language differences that are legal in both languages but that would produce different behavior. The sizeof (char) difference that Naveen mentioned is one example, but Write a program that will print "C" if compiled as an (ANSI) C program, and "C++" if compiled as a C++ program lists some others.

Community
  • 1
  • 1
jamesdlin
  • 81,374
  • 13
  • 159
  • 204
-2

C compilers generally allowed a little corner cutting that C++ doesn't. C++ is much more strict than C. And generally, some of these differences are compiler-dependant. g++ allows some things that the Intel C++ compiler doesn't, for instance. Even fairly well written C code won't compile with a modern C++ compiler.

xcramps
  • 1,203
  • 1
  • 9
  • 9