views:

556

answers:

5

If you take an existing C code base and compile it with a C++ compiler, what sort of issues can you expect to crop up? For example, I think that assigning an integer to an value with an enumerated type will fail in C++, whereas it's legal ( if a bit nasty ) in C.

If I don't wrap all my C files in "extern C { ... }", am I going to get name-mangling where I least expect it? Is there some reason why I really shouldn't do this?

For background, we have a very large code-base written in C. For a few years we've been jumping through hoops to do things that would come naturally via C++ ( homebrewed inheritance, for example ). We'd like to start moving towards C++, but in a gradual fashion; getting our CORBA-like framework to support it, and refactoring modules as we go along to take advantage of the more natural approach C++ would provide.

+10  A: 

See Incompatibilities between ISO C and ISO C++ for a very detailed list of all of the incompatibilities. There are a lot of subtle issues, including some which don't immediately manifest in a compiler error. For example, one issue that can be a problem is the size of character constants:

// In C, prints 4.  In C++, prints 1
printf("%d\n", sizeof('A'));
Adam Rosenfield
+7  A: 

I've done something like this once. The main source of problems was that C++ is more strict about types, as you suspected. You'll have to add casts where void* are mixed with pointers of other types. Like allocating memory:

Foo *foo;
foo = malloc(sizeof(*foo));

The above is typical C code, but it'll need a cast in C++:

Foo *foo;
foo = (Foo*)malloc(sizeof(*foo));

There are new reserved words in C++, such as "class", "and", "bool", "catch", "delete", "explicit", "mutable", "namespace", "new", "operator", "or", "private", "protected", "friend", etc. These cannot be used as variable names, for example.

The above are probably the most common problems when you compile old C code with a C++ compiler. For a complete list of incompatibilities, see Incompatibilities Between ISO C and ISO C++.

You also ask about name mangling. In absence of extern "C" wrappers, the C++ compiler will mangle the symbols. It's not a problem as long as you use only a C++ compiler, and don't rely on dlsym() or something like that to pull symbols from libraries.

Ville Laurikari
Some of the C++ reserved words are also keywords under some circumstances - #include <iso646.h>, #include <stdbool.h>, etc.
Jonathan Leffler
"There are new reserved words in C++". The one I've fallen over was "this". When you have vaguely OO C code, there's a good chance someone has used it to mean, well, what it means in C++...
Steve Jessop
Ouch! I had forgotten about that. We have very OO code code, and lots of uses of 'this' in our component archetecture. Now one of my developers will get to say "I told you so", as he did warn me during a code review that I probably shouldn't use 'this'.
Chris Arguin
+1  A: 

Another example: there's not an implicit conversion from ints to enums in C++, while there's one in C. You'll need a cast if you really want to do it in C++.

piotr
+1  A: 

C++ has stricter type checking, so you might need to add a cast to each call to malloc/realloc/calloc.

immibis
+4  A: 

If I don't wrap all my C files in "extern C { ... }", am I going to get name-mangling where I least expect it?

It bites you when you try to link together C and C++.

I've written a lot of header files containing:

#ifdef __cplusplus
    extern "C" {
#endif

// rest of file

#ifdef __cplusplus
    }
#endif

After a while it merges into the existing multiple-include boilerplate and you stop seeing it. But you do have to be careful where you put it - usually it belongs after any includes your header does.

Is there some reason why I really shouldn't do this?

If you know for sure you aren't going to combine C and C++ then there's no reason to do it that I know of. But with the gradual migration you describe, it's essential for anything with a published interface that both C components and C++ components need to use.

The big reason not to do it is that it prevents you from overloading functions (at least, in those headers). You might find you want to do that once you've migrated all your code to C++ and started maintaining/refactoring/extending it.

Steve Jessop