Having just started on pretty much the same thing a few months ago (on a ten-year-old commercial project, originally written with the "C++ is nothing but C with smart structs" philosophy), I would suggest using the same strategy you'd use to eat an elephant: take it one bite at a time. :-)
As much as possible, split it up into stages that can be done with minimal effects on other parts. Building a facade system, as Federico Ramponi suggested, is a good start -- once everything has a C++ facade and is communicating through it, you can change the internals of the modules with fair certainty that they can't affect anything outside them.
We already had a partial C++ interface system in place (due to previous smaller refactoring efforts), so this approach wasn't difficult in our case. Once we had everything communicating as C++ objects (which took a few weeks, working on a completely separate source-code branch and integrating all changes to the main branch as they were approved), it was very seldom that we couldn't compile a totally working version before we left for the day.
The change-over isn't complete yet -- we've paused twice for interim releases (we aim for a point-release every few weeks), but it's well on the way, and no customer has complained about any problems. Our QA people have only found one problem that I recall, too. :-)
Answer from Head Geek on Stack OverflowConverting C source to C++ - Stack Overflow
How to convert C++ Code to C - Stack Overflow
How can I convert my C code into C++?
How to convert C++ Code to C
Pretty much, yes.
The classes become structs with a (separate) set of functions; usually you prefix the names so itโs clear what they act on. Youโll need to to manual de-/initialization too. E.g.,
class C {
private:
int x;
public:
C() : x(0) {}
C(const C &c) : x(c.x) {}
C(int xv) : x(xv) {}
int getX() const {return x;}
};becomes something like
typedef struct C C;
struct C {
int x;
/* If you need to, you can also partition this like
struct {
int x;
} private__;
but itโs not like the C compiler will actually enforce privateness. */
};
void C_init_1(C *const inst) {inst->x = 0;}
void C_copy(C *const inst, const C *const c) {inst->x = c->x;}
void C_init_2(C *const inst, int cv) {inst->x = cv;}
int C_getX(const C *const inst) {return inst->x;}
If C extends something, it has to start with a copy of that thing; e.g.,
class D : public E, public F {โฆ};becomes
typedef struct D D;
struct D {
E super_E;
F super_F;
};
so static upcasting from D to E becomes &inst->super_E and the reverse is something like (struct D *)((char *)inst - offsetof(D, super_E)).
Virtual stuff gets into a whole other layer of crazy. A class with virtual members (including inherited ones) becomes something like
typedef struct V V;
struct V__vtable;
struct C {
const struct V__vtable *vtable__;
โฆ
};
struct V__vtable {
(virtual function pointers here)
};and then you have to figure out a way to do dynamic casting (exercise for the reader:).
Templates usually end up as macros, and thereโs really no good way to handle that uniformly; youโll have to manually come up with names for the template instantiations and make sure things get pasted together properly. They might not be as bad if you use a separate header for each template and take macro args (#undef at end of file), then #include the header whenever you need to instantiate the template.
So you can do it, but itโs almost not worth it if you have any way to just shim into the C++ code from C. (E.g., come up with some extern "C" functions that let you access the C++ side of things.)
Is the C to C++ converter free?
Can I also convert C++ back to C?
What types of C code can be converted to C++?
Videos
Having just started on pretty much the same thing a few months ago (on a ten-year-old commercial project, originally written with the "C++ is nothing but C with smart structs" philosophy), I would suggest using the same strategy you'd use to eat an elephant: take it one bite at a time. :-)
As much as possible, split it up into stages that can be done with minimal effects on other parts. Building a facade system, as Federico Ramponi suggested, is a good start -- once everything has a C++ facade and is communicating through it, you can change the internals of the modules with fair certainty that they can't affect anything outside them.
We already had a partial C++ interface system in place (due to previous smaller refactoring efforts), so this approach wasn't difficult in our case. Once we had everything communicating as C++ objects (which took a few weeks, working on a completely separate source-code branch and integrating all changes to the main branch as they were approved), it was very seldom that we couldn't compile a totally working version before we left for the day.
The change-over isn't complete yet -- we've paused twice for interim releases (we aim for a point-release every few weeks), but it's well on the way, and no customer has complained about any problems. Our QA people have only found one problem that I recall, too. :-)
What about:
- Compiling everything in C++'s C subset and get that working, and
- Implementing a set of facades leaving the C code unaltered?
Why is "translation into C++ mandatory"? You can wrap the C code without the pain of converting it into huge classes and so on.
There is indeed such a tool, Comeau's C++ compiler. . It will generate C code which you can't manually maintain, but that's no problem. You'll maintain the C++ code, and just convert to C on the fly.
http://llvm.org/docs/FAQ.html#translatecxx
It handles some code, but will fail for more complex implementations as it hasn't been fully updated for some of the modern C++ conventions. So try compiling your code frequently until you get a feel for what's allowed.
Usage sytax from the command line is as follows for version 9.0.1:
clang -c CPPtoC.cpp -o CPPtoC.bc -emit-llvm
clang -march=c CPPtoC.bc -o CPPtoC.c
For older versions (unsure of transition version), use the following syntax:
llvm-g++ -c CPPtoC.cpp -o CPPtoC.bc -emit-llvm
llc -march=c CPPtoC.bc -o CPPtoC.c
Note that it creates a GNU flavor of C and not true ANSI C. You will want to test that this is useful for you before you invest too heavily in your code. For example, some embedded systems only accept ANSI C.
Also note that it generates functional but fairly unreadable code. I recommend commenting and maintain your C++ code and not worrying about the final C code.
EDIT : although official support of this functionality was removed, but users can still use this unofficial support from Julia language devs, to achieve mentioned above functionality.