Most C++ compilers will process both C source code files, files with a .c extension, and C++ source code files, files with a .cpp extension. So the first step in a conversion would be to change to a C++ compiler and get your project files and/or make files in order so that it all compiles.
The next thing is to go through the source code base to determine what data structures are going to change and which include files, normally files with a .h extension, have these data structures that will need to change.
At this point you will need to begin partitioning out what source is C++ and what source is C. For instance while C struct
is a subset of the C++ struct
, C++ struct
allows for constructors and deconstructors which C does not allow. This means you can use a C struct
with C++ source but you can not use a C++ struct
with the C++ features in a C source file.
Other C++ language keywords such as class
just won't work period with a C source code file.
Next is to look at what C++ features, such as templates and C++ Standard Library functionality such as std::string
, you are going to use. Again you will need to partition off the C++ source from the C.
The extern "C"
functionality allows you to use C functions with C++ source code by declaring a function or variable name as being C rather than C++. This is necessary because the C++ compiler does name mangling, using an algorithm to generate a modified name for functions allowing function overloading. See What is name mangling, and how does it work?
The other thing you will be faced with is that C++ has introduced new versions of most of the standard C include files without the .h extension. You can use the old version with C++ but the new versions are preferred since they are for C++. However C source files can only use the old, .h extension, version of these files.
Conditional compilation for header files
The magic that allows the use of the older standard C include files with C++ source code is that most compilers have a special #define
which can be used to do conditional compilation. With the Visual Studio compiler the special define is __cplusplus
and it can be used something like:
#if defined(__cplusplus)
extern "C" {
#endif
// The type CONNENGINEHANDLE is for future expansion to allow multiple
// sockets to be managed by the dll.
typedef unsigned short CONNENGINEHANDLE;
// following functions are used with a server implementation.
// these functions will setup the parameters for the server and
// start the listen needed to accept a connection from a client
CONNENGINE_API int fnConnEngineSetDomainNamePort(CONNENGINEHANDLE hConnEngineSocket, char *aszDomainName, int nPortNo);
CONNENGINE_API int fnConnEngineStartEngine (int nPort, HWND hWinHandle, UINT wReceiveMsgId);
CONNENGINE_API int fnConnEngineStopEngine ();
#if defined(__cplusplus)
};
#endif
What the above preprocessor code that is part of an include file does is to allow a C++ source code file to include the same header file as C source code files but when it is included in the C++ file, the extern "C" {
is part of the header file text because the Preprocessor has the __cplusplus
defined. So the C++ source is able to use functions defined in the C source code and the name mangling ordinarily done with C++ is turned off for those functions whose declarations are within the braces.
However though this special #define
to detect if a C++ source file is being processed by the Preprocessor you still can't use C++ language constructs in C source files. You will still need to partition out the C++ from the C.
Interface functions for C calling C++ functionality
In some cases you may need to execute C++ source code functionality from C source code functionality. In those cases you will need to create a C compatible interface to the C++ functionality.
For instance if you have a struct
that contains a std::string
, which is incompatible with C source code, you can create the C++ source code to hide the implementation details and to then provide a C compatible interface.
For instance from the include file example showing the use of __cplusplus
above, one of those functions is defined in a C++ source code file as follows. This C++ source code file also include the same header file as would be used with a C source code file and with the declaration above for the function fnConnEngineStartEngine()
, the C++ compiler knows it is not supposed to name mangle the function name fnConnEngineStartEngine{}
. This C++ source code provides an interface between C source that uses the C++ object theApp
.
CONNENGINE_API int fnConnEngineStartEngine (int nPort, HWND hWinHandle, UINT wReceiveMsgId)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
if (hWinHandle == 0)
hWinHandle = theApp.m_hWinHandle;
if (wReceiveMsgId == 0)
wReceiveMsgId = theApp.m_wReceiveMsgId;
theApp.StartEngineAsServer (nPort, hWinHandle, wReceiveMsgId);
return 0;
}