How to Mix C++ and C Correctly

How to mix C++ and C correctly

Here is a working example:

wrapper.h (C & C++ aware)

#ifndef WRAPPER_H_
#define WRAPPER_H_

#ifdef __cplusplus
extern "C" {
#endif

typedef struct CPPClass CPPClass;

CPPClass* CPPClass_new();
void CPPClass_do_something(CPPClass* cppclass);
int CPPClass_get_state(CPPClass* cppclass);
void CPPClass_delete(CPPClass* cppclass);

#ifdef __cplusplus
}
#endif
#endif /* WRAPPER_H_ */

wrapper.cpp (C++ only)

#include "wrapper.h"

class CPPClass
{
int state;
public:
CPPClass(): state(0) {}
void do_something() { ++state; }
int get_state() const { return state; }
};

extern "C" CPPClass* CPPClass_new()
{
return new CPPClass;
}

extern "C" void CPPClass_do_something(CPPClass* cppclass)
{
cppclass->do_something();
}

extern "C" int CPPClass_get_state(CPPClass* cppclass)
{
return cppclass->get_state();
}

extern "C" void CPPClass_delete(CPPClass* cppclass)
{
delete cppclass;
}

use-wrapper.c (C only)

#include <stdio.h>
#include "wrapper.h"

int main(void)
{
CPPClass* cppclass = CPPClass_new();

if(!cppclass)
{
printf("ERROR: failed to create CPPClass:\n");
return 1;
}

printf("state: %d\n", CPPClass_get_state(cppclass));
CPPClass_do_something(cppclass);
printf("state: %d\n", CPPClass_get_state(cppclass));

CPPClass_delete(cppclass);
}

Compile CPP

g++ -std=c++11 -shared -fPIC -o libwrapper.so wrapper.cpp

Compile C

gcc -o use-wrapper use-wrapper.c -L. -lwrapper -lstdc++

Output:

$ ./use-wrapper 
state: 0
state: 1

Hope that helps.

Using/Mixing C in C++ code?

I keep telling them that as long as you know what your doing, and you delete your new's and free your malloc's then C isn't a problem.

This is true; if you are extraordinarily careful and ensure that you manually clean things up, then it isn't a problem. But do you really have the time to do that? Every call to new can throw std::bad_alloc. Do you always catch every exception that can be thrown and manually clean up any resources?

I'd hazard to guess the answer to that is "no," because it is very tedious to write code like that and it is difficult to be absolutely sure that code written like that is correct, even in the case of rare failures.

If the answer is "yes," then why are you wasting so much time worrying about resource management? C++ idioms like scope-bound resource management (SBRM; more commonly known as resource acquisition is initialization (RAII)) and libraries like the standard template library are there to help you write correct code more easily. Why do things the hard way when you don't have to?

Should you ONLY use 100% C++ when your coding C++?

Yes, though if there is a C library that does something you need, or if you have legacy C code that you want to use, you can certainly use that code; just be sure to be careful. Often the cleanest way to interop with C code is to write a C++ wrapper around it.

Trouble compiling/linking C and C++ files

If you want g++ to compile an object module without linking it into a complete program then you must give it the -c option:

g++ -c loader.cpp -o loader.o

Note that that compilation command also assigns a conventional name to the generated object file, and that if you're not linking it into an executable then you don't need to specify libraries to link it to. Your Makefile is already set up for this.

If you add loader.o to the dependencies of CSCIx229.a then that should be enough to persuade make to build it from loader.cpp and to include the object file in your library (which will make it available for linking into your executables). You may also need to add some or all of -lGLU -lGL -lglut to your LIBS variable. It might also be appropriate to add loader.o's dependencies to the makefile if they include more than just loader.cpp itself (e.g. if they include CSCIx229.h).

Combining large C and C++ programs

1) Should I wrap my C header files with extern "C" {}?

2) Should I use extern "C" in my C functions?

Only if you plan to #include the C headers from some C++ source files, i.e., if you want to call one of the C functions from your C++ code. The typical way to make a C header file usable in C++, is like this:

#ifndef MY_C_HEADER_H
#define MY_C_HEADER_H

#ifdef __cplusplus
extern "C" {
#endif

/* All the original content of the C header */

#ifdef __cplusplus
}
#endif

#endif

If you don't want to modify the header, it is also possible to simply apply the extern "C" from the outside of the header when including it in a C++ source file:

// in my_source.cpp (or some C++ header file):

extern "C" {

#include "my_c_header.h"

}

NOTE: Doing that solution is not at all recommended nor is it a long-term / maintainable solution, it is just a quick-and-dirty "just make it work" solution that often fails, but sometimes works, depending on how the C headers look like (C headers don't need to include many other headers, and shouldn't in general, but some authors don't have the common sense to do so).

The reason for extern "C" is to disable C++ name-mangling, i.e., tell the compiler that the functions should be compiled to correspond to un-mangled symbols and/or should be looked up in the symbol table un-mangled (when linking to them). So, the rule is simple, any C++ functions that you want to compile into a library that would be callable from C code (or any other language for that matter) needs to be declared as extern "C". And any function declarations that you which to call in C++ code but links to a library compiled from C (or any other language) must be extern "C" as well.

3) Or should I use extern "C" in my C++ files? (headers? functions? all of them? or only those I need to call from the C program?)

If you want to call some C++ functions from your C code, then those specific functions will have to be declared as extern "C" when compiling that C++ code. In the C header file that declares those functions (for the purpose of calling them from the C code), there is no need for extern "C" (it is always implied in C).

4) In understand I can not have two 'main' functions. Can I simply rename my C++ 'main' function?

What would be the purpose of two main functions? It is not allowed and not useful. You can still just have one "program" with one start and one end, i.e., one main function. You'll have to pick one of the main functions, and add to it whatever extra steps you want (calling the other library). In other words, you have to "merge" the main functions.

5) When compiling in unix, should I use both C (icc) and C++ (icpc) compilers for different files? or just the C++ compiler?

You use the C compiler to compile the C code and a C++ compiler to compile the C++ code. Most build systems (cmake, make, etc.) will automatically do that anyways. Technically, you could try and compile the C code using the C++ compiler, but don't expect it to work right away or even be easy at all to get it working, not worth the effort IMHO.

6) Could it be an option (to simplify things) to convert my main function from C to C++?

That is an option. You source file containing the C main function seems relatively simple, it includes one C header file and has a fairly simple main function. If so, this won't be hard to get to compile on a C++ compiler (unless the C header that it includes is a lot of other C headers, which is bad practice, but likely). You will need to wrap the C header file inclusion with the extern "C" { } as shown above. Then, you can just try to compile it (only the source file containing the main function) in a C++ compiler, and the rest of the C code with the C compiler, and then link the whole thing together. If that works right away, then great, you can start to merge that C main function with the C++ main function from the other library, and you will be good to go.

Otherwise, the usual option is to figure out what you need the C++ code to do. Then, create a C-friendly function (no classes, etc.) in C++ that does these things, using the C++ library. Then, create a header file that declares that function, with the extern "C" specifier (when compiling under C++ only (__cplusplus)), and make sure that this header does not include any other C++ header (not standard headers, not any other headers from the C++ library). And finally, in your C source code, where you have the main function, include that header and call that function(s) from where you need it in the main function. Link the whole thing together and it should work.

7) If I don't need to pass information of classes between the two programs, do I need to do anything about them?

No. As long as you don't include any C++ header from the C code (which the compiler won't accept anyways), the C code is not aware that classes even exist. So, there is no danger here.

8) In what order do you suggest this problem to be tackled? (e.g. first have my C program compiled by C++ compiler; second, compile both codes together with no links; third, link the codes; fourth, rename main in C++ and have it "called" by my C code; fifth, implement the transfer of information?)

First step is, of course, to make sure you can compile both separately. Second step is to see if it is possible to compile the C program's main function (only the main function) with a C++ compiler (as explained above). If successful, start incorporating elements from the C++ main function into that new "merged" main function. If unsuccessful, follow the steps that I just mentioned.

9) Finally, there are some macros in each program, which are repeated (same name, same implementation). Is there a conflict with this? Should I only keep one set of macros?

MACROs... that's hard to tell. If you follow the procedure of creating a C++ function that can be called from the C main function, then you essentially have a perfect isolation of both libraries, i.e., they are compiled separately and linked together after. In that case, there will be no problem with conflicting MACROs (but there might be with functions of the same name, if some are extern "C" in the C++ library). If you try to merge the main functions into one C++ main function, you might have some problems with conflicting MACROs between the C headers and C++ headers which will be included together.

Makefile with mixed c and C++ code

To be able to call C functions from C++ (or C++ functions from C) you have to prevent the C++ name mangling, so that the linker will work properly.

That is, C function int add(int, int) actually generates a symbol in the object file called add. But a C++ function int add(int, int) will generate a symbol named _Z3addii. And those will not link.

Solution: the mixed language functions, when compiled in with C++ should be declared extern "C". Unfortunately the extern "C" declaration does not exist in C, only in C++.

So the standard idiom is:

test1.h

#ifndef _FILE_H
#define _FILE_H

#ifdef __cplusplus
extern "C" {
#endif

int add(int a, int b);

#ifdef __cplusplus
} //extern "C"
#endif

#endif

That way, the C code is just as before, but the C++ code will look for the add function using the undecoraded name, and all will link together.

What is the effect of extern C in C++?

extern "C" makes a function-name in C++ have C linkage (compiler does not mangle the name) so that client C code can link to (use) your function using a C compatible header file that contains just the declaration of your function. Your function definition is contained in a binary format (that was compiled by your C++ compiler) that the client C linker will then link to using the C name.

Since C++ has overloading of function names and C does not, the C++ compiler cannot just use the function name as a unique id to link to, so it mangles the name by adding information about the arguments. A C compiler does not need to mangle the name since you can not overload function names in C. When you state that a function has extern "C" linkage in C++, the C++ compiler does not add argument/parameter type information to the name used for linkage.

Just so you know, you can specify extern "C" linkage to each individual declaration/definition explicitly or use a block to group a sequence of declarations/definitions to have a certain linkage:

extern "C" void foo(int);
extern "C"
{
void g(char);
int i;
}

If you care about the technicalities, they are listed in section 7.5 of the C++03 standard, here is a brief summary (with emphasis on extern "C"):

  • extern "C" is a linkage-specification
  • Every compiler is required to provide "C" linkage
  • A linkage specification shall occur only in namespace scope
  • All function types, function names and variable names have a language linkage See Richard's Comment: Only function names and variable names with external linkage have a language linkage
  • Two function types with distinct language linkages are distinct types even if otherwise identical
  • Linkage specs nest, inner one determines the final linkage
  • extern "C" is ignored for class members
  • At most one function with a particular name can have "C" linkage (regardless of namespace)
  • extern "C" forces a function to have external linkage (cannot make it static) See Richard's comment: static inside extern "C" is valid; an entity so declared has internal linkage, and so does not have a language linkage
  • Linkage from C++ to objects defined in other languages and to objects defined in C++ from other languages is implementation-defined and language-dependent. Only where the object layout strategies of two language implementations are similar enough can such linkage be achieved

Cannot Call C++ Code from C without Error

mylibrary.o still depends on C++ standard library and gcc doesn't know about it. Call gcc with -lstdc++ in the last step.

calling .c file inside .cpp

Given these contents of dispmanx.c:

#ifdef __cplusplus
extern "C" {
#endif

#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <assert.h>
#include <unistd.h>
#include <sys/time.h>

and main.cpp starts with

#include "dispmanx.c"

You are going to have serious problems.

You've wrapped entire standard header files such as unistd.h with extern "C", and then #include'd them in a C++ file.

They're not meant to be used that way in C++ code.

#include'ing a source file (.c, .cpp, etc) is a fundamentally bad idea in the first place. Doing it across different languages such a C and C++ and then improperly wrapping system headers with extern "C" is even worse. You can't safely compile C code as C++ code, and you certainly can't wrap system header files with extern "C" for use in C++ code.

extern "C" does not make it safe to compile C code with a C++ compiler. They are different languages, with subtle distinctions.

Combining C++ and C - how does #ifdef __cplusplus work?

extern "C" doesn't really change the way that the compiler reads the code. If your code is in a .c file, it will be compiled as C, if it is in a .cpp file, it will be compiled as C++ (unless you do something strange to your configuration).

What extern "C" does is affect linkage. C++ functions, when compiled, have their names mangled -- this is what makes overloading possible. The function name gets modified based on the types and number of parameters, so that two functions with the same name will have different symbol names.

Code inside an extern "C" is still C++ code. There are limitations on what you can do in an extern "C" block, but they're all about linkage. You can't define any new symbols that can't be built with C linkage. That means no classes or templates, for example.

extern "C" blocks nest nicely. There's also extern "C++" if you find yourself hopelessly trapped inside of extern "C" regions, but it isn't such a good idea from a cleanliness perspective.

Now, specifically regarding your numbered questions:

Regarding #1: __cplusplus will stay defined inside of extern "C" blocks. This doesn't matter, though, since the blocks should nest neatly.

Regarding #2: __cplusplus will be defined for any compilation unit that is being run through the C++ compiler. Generally, that means .cpp files and any files being included by that .cpp file. The same .h (or .hh or .hpp or what-have-you) could be interpreted as C or C++ at different times, if different compilation units include them. If you want the prototypes in the .h file to refer to C symbol names, then they must have extern "C" when being interpreted as C++, and they should not have extern "C" when being interpreted as C -- hence the #ifdef __cplusplus checking.

To answer your question #3: functions without prototypes will have C++ linkage if they are in .cpp files and not inside of an extern "C" block. This is fine, though, because if it has no prototype, it can only be called by other functions in the same file, and then you don't generally care what the linkage looks like, because you aren't planning on having that function be called by anything outside the same compilation unit anyway.

For #4, you've got it exactly. If you are including a header for code that has C linkage (such as code that was compiled by a C compiler), then you must extern "C" the header -- that way you will be able to link with the library. (Otherwise, your linker would be looking for functions with names like _Z1hic when you were looking for void h(int, char)

5: This sort of mixing is a common reason to use extern "C", and I don't see anything wrong with doing it this way -- just make sure you understand what you are doing.



Related Topics



Leave a reply



Submit