C and C++ linkage with extern "C" - c++

I have a C++ function defined in a .h file as follows and implemented in a .cpp file:
extern "C" void func(bool first, float min, float* state[6], float* err[6][6])
{
//uses vectors and classes and other C++ constructs
}
How can I call func in a C file? How do I set up my file architecture / makefile to compile this?
Thanks!

You call the function from C in the normal way. However, you need to wrap the extern "C" in an preprocessor macro to prevent the C compiler from seeing it:
#ifndef __cplusplus
extern "C"
#endif
void func(bool first, float min, float* state[6], float* err[6][6]);
Assuming you're working with GCC, then compile the C code with gcc, compile the C++ code with g++, and then link with g++.

To call it in C, all you need to do is call it normally. Because you told the compiler to use the C calling conventions and ABI with extern "C", you can call it normally:
func(args);
To compiler, use this for the C++:
g++ -c -o myfunc.o myfunc.cpp
Then this for the C:
gcc -c -o main.o somec.c
Than link:
g++ -o main main.o myfunc.o
Make sure that the C++ header for the function uses ONLY C CONSTRUCTS. So include things like <vector> in the .cpp file instead.

call it in C using
func(/* put arguments here */);
By saying extern "C" you are asking the compiler not to mangle your names. Otherwise, C++ compiler would tend to mangle them (i.e. add additional symbols to make them unique) before the linker.
You'll also want to make sure you have setup to use C calling convention.

//header file included from both C and C++ files
#ifndef __cplusplus
#include <stdbool.h> // for C99 type bool
#endif
#ifdef __cplusplus
extern "C" {
#endif
void func(bool first, float min, float* state[6], float* err[6][6]);
#ifdef __cplusplus
} // extern "C"
#endif
// cpp file
#include "the_above_header.h"
#include <vector>
extern "C" void func(bool first, float min, float* state[6], float* err[6][6]);
{
//uses vectors and classes and other C++ constructs
}
// c file
#include "the_above_header.h"
int main() {
bool b;
float f;
float *s[6];
float *err[6][6];
func(b,f,s,err);
}

Related

Why is __cplusplus defined within extern "C"

Within extern "C" { } the macro __cplusplus is still defined. When I want to include the C version of mpi.h in the header of my library which is dynamically load this will not work as mpi.h still finds __cplusplus and will still load like it was opened by C++.
#undef __cplusplus works with gcc. But I do not want to rely on this.
So how to write a C++ program that
- uses the C++ version of mpi and
- is linked against a C-library that uses the C-Version of mpi (where #include <mpi.h> appears already in the header?
Example code:
library.h:
#ifdef __cplusplus
extern "C" {
#endif
#include <mpi.h>
void library_do(MPI_Comm comm);
#ifdef __cplusplus
}
#endif
program.cpp:
#include <library.h>
#include <mpi.h>
int main() {
MPI::Init();
// do some mpi C++ calls...
library_do(MPI::COMM_WORLD);
MPI::Finalize();
}
In case somebody wants to play the example here the library.c:
#include <stdio.h>
#include "library.h"
void library_do(MPI_Comm comm)
{
int rank;
MPI_Comm_rank(comm, &rank);
printf("MPI Rank: %d", rank);
}
And to compile everything I try with
mpicc -shared library.c -o lib.so
mpicxx program.cpp -l lib.so
__cplusplus will always be defined by the compiler if the compiler is a C++ compiler. extern "C" {} only gives you C linkage so the code inside plays nice with a C compiler.
The point of using
#ifdef __cplusplus
extern "C" {
#endif
...
#ifdef __cplusplus
}
#endif
is to prevent the name mangling that C++ does. We are basically saying dont use the name mangling like a traditional C++ function call instead leave it undecorated.
This link could be useful Name mangling
It is used to make C headers compatible with C++.
The flag __cplusplus is automatically defined in C++ compiler.
Because they are different things. extern "C" {} tells the compiler how to export symbols (see here), whereas __cplusplus tells you that you can use C++ code so your library can use different code paths inbetween #ifdefs.
The compiler outputs the following:
In file included from /usr/include/c++/4.8.2/bits/stl_algobase.h:61:0,
from /usr/include/c++/4.8.2/bits/stl_tree.h:61,
from /usr/include/c++/4.8.2/map:60,
from /usr/include/openmpi-x86_64/openmpi/ompi/mpi/cxx/mpicxx.h:38,
from /usr/include/openmpi-x86_64/mpi.h:2674,
from x1.cpp:6:
/usr/include/c++/4.8.2/bits/cpp_type_traits.h:72:3: error: template with C linkage
template<typename _Iterator, typename _Container>
^
/usr/include/c++/4.8.2/bits/cpp_type_traits.h:85:3: error: template with C linkage
template<bool>
^
...
The mpi.h header detects that it's being compiled as C++ and so includes C++ specific features. However templates (among other things) don't work with C linkage (i.e. if the header is within an extern "C" block).
Move the include above extern "C":
#include <mpi.h>
#ifdef __cplusplus
extern "C" {
#endif
void library_do(MPI_Comm comm);
#ifdef __cplusplus
}
#endif
Of course it's defined. It's still a C++ compiler that compiled the code inside the extern "C" block. It doesn't stop treating the code as C++, only makes sure to use a C calling/naming convention.
If the header cannot be compiled by a C++ compiler, the only recourse is to create a C wrapper that exposes a C++ compatible API.
If you #include <mpi.h> from a C++ program, just don't put extern "C" around it. At least OpenMPI and Intel MPI do this for you in the header itself - if __cplusplus is defined.
You probably get into trouble because some MPI implementations still define the C++ interface in mpi.h that was deleted from the standard. This obviously breaks under extern "C". For instance with OpenMP you can skip this by setting OMPI_SKIP_MPICXX. Then the double extern "C" works, but I still wouldn't recommend it.
Update: In case you can't modify the library header, just #include <mpi.h> before #include <lib.h>.
That said, you should not use the C++ bindings for MPI. They were removed from the standard more than 6 years ago, after being for 3 years...

Include and compile C++ header file from C

I have a C++ file and its header file. I need to include this header file in a C code and use the functions in it.
When the cpp.h file is compiled through main.c, compilation fails because of the C++ linkage.
On using the macro __cplusplus stream and string are not resolved, is there some way to compile the cpp.h file through and execute?
I have given a outline of my code only.
C++ header file cpp.h:
struct s1
{
string a;
string b;
};
typedef struct s1 s2;
class c1
{
public:
void fun1(s2 &s3);
private:
fun2(std::string &x,const char *y);
};
C++ file cpp.cpp:
c1::fun1(s2 &s3)
{
fstream file;
}
c1::fun2(std::string &x,const char *y)
{
}
C file main.c:
#include "cpp.h"
void main()
{
c1 c2;
s1 structobj;
c2.fun1(&structobj);
printf("\n value of a in struct %s",structobj.a);
}
Basically, you can't.
You need to put only C functions in your header file.
You put them in a extern "C" block this way:
#ifdef __cplusplus
extern "C"
{
#endif
extern void myCppFunction(int n);
#ifdef __cplusplus
}
#endif
The extern "C" block is not recognized by a C compiler, but the C++ compiler need it to understand he have to consider functions inside as C functions.
In your cpp file you can define myCppFunction() so that she uses any C++ code, you will get a function C code can use.
Edit: I add a full example of how to link a program with a C main() using some C++ functions in a module.
stackoverflow.c:
#include "outputFromCpp.h"
int main()
{
myCppFunction(2000);
return 0;
}
outputFromCpp.h:
#ifndef OUTPUT_FROM_CPP_H
#define OUTPUT_FROM_CPP_H
#ifdef __cplusplus
extern "C"
{
#endif
extern void myCppFunction(int n);
#ifdef __cplusplus
}
#endif
#endif
outputFromCpp.cpp:
#include "outputFromCpp.h"
#include <iostream>
using namespace std;
void myCppFunction(int n)
{
cout << n << endl;
}
Compiling and linking:
gcc -Wall -Wextra -Werror -std=gnu99 -c stackoverflow.c
g++ -Wall -Wextra -Werror -std=c++98 -c outputFromCpp.cpp
g++ -o stackoverflow.exe stackoverflow.o outputFromCpp.o -static
You cannot link such a program with gcc.
If you want to link with gcc you need to put all the C++ code in a shared library, I don't put an example as it would be a bit platform dependent.
This can be done by introducing a wrapper to c++ function. The C function calls the wrapper function which inturn calls the desired C++ function (including member functions).
More details are available here

Call a C function from C++ code

I have a C function that I would like to call from C++. I couldn't use "extern "C" void foo()" kind of approach because the C function failed to be compiled using g++. But it compiles fine using gcc. Any ideas how to call the function from C++?
Compile the C code like this:
gcc -c -o somecode.o somecode.c
Then the C++ code like this:
g++ -c -o othercode.o othercode.cpp
Then link them together, with the C++ linker:
g++ -o yourprogram somecode.o othercode.o
You also have to tell the C++ compiler a C header is coming when you include the declaration for the C function. So othercode.cpp begins with:
extern "C" {
#include "somecode.h"
}
somecode.h should contain something like:
#ifndef SOMECODE_H_
#define SOMECODE_H_
void foo();
#endif
(I used gcc in this example, but the principle is the same for any compiler. Build separately as C and C++, respectively, then link it together.)
Let me gather the bits and pieces from the other answers and comments, to give you an example with cleanly separated C and C++ code:
The C Part:
foo.h:
#ifndef FOO_H
#define FOO_H
void foo(void);
#endif
foo.c
#include "foo.h"
void foo(void)
{
/* ... */
}
Compile this with gcc -c -o foo.o foo.c.
The C++ Part:
bar.cpp
extern "C" {
#include "foo.h" //a C header, so wrap it in extern "C"
}
void bar() {
foo();
}
Compile this with g++ -c -o bar.o bar.cpp
And then link it all together:
g++ -o myfoobar foo.o bar.o
Rationale:
The C code should be plain C code, no #ifdefs for "maybe someday I'll call this from another language". If some C++ programmer calls your C functions, it's their problem how to do that, not yours. And if you are the C++ programmer, then the C header might not be yours and you should not change it, so the handling of unmangled function names (i.e. the extern "C") belongs in your C++ code.
You might, of course, write yourself a convenience C++ header that does nothing except wrapping the C header into an extern "C" declaration.
I agree with Prof. Falken's answer, but after Arne Mertz's comment I want to give a complete example (the most important part is the #ifdef __cplusplus):
somecode.h
#ifndef H_SOMECODE
#define H_SOMECODE
#ifdef __cplusplus
extern "C" {
#endif
void foo(void);
#ifdef __cplusplus
}
#endif
#endif /* H_SOMECODE */
somecode.c
#include "somecode.h"
void foo(void)
{
/* ... */
}
othercode.hpp
#ifndef HPP_OTHERCODE
#define HPP_OTHERCODE
void bar();
#endif /* HPP_OTHERCODE */
othercode.cpp
#include "othercode.hpp"
#include "somecode.h"
void bar()
{
foo(); // call C function
// ...
}
Then you follow Prof. Falken's instructions to compile and link.
This works because when compiling with gcc, the macro __cplusplus is not defined, so the header somecode.h included in somecode.c is like this after preprocessing:
void foo(void);
and when compiling with g++, then __cplusplus is defined, and so the header included in othercode.cpp is now like that:
extern "C" {
void foo(void);
}
This answer is inspired by a case where Arne's rationale was correct. A vendor wrote a library which once supported both C and C++; however, the latest version only supported C. The following vestigial directives left in the code were misleading:
#ifdef __cplusplus
extern "C" {
#endif
This cost me several hours trying to compile in C++. Simply calling C from C++ was much easier.
The ifdef __cplusplus convention is in violation of the single responsibility principle. A code using this convention is trying to do two things at once:
(1) execute a function in C
-- and --
(2) execute the same function in C++
It's like trying to write in both American and British English at the same time. This is unnecessarily throwing an #ifdef __thequeensenglish spanner #elif __yankeeenglish wrench #else a useless tool which makes the code harder to read #endif into the code.
For simple code and small libraries the ifdef __cplusplus convention may work; however, for complex libraries it is best to pick one language or the other and stick with it. Supporting one of the languages will take less maintenance than trying to support both.
This is a record of the modifications I made to Arne's code to get it to compile on Ubuntu Linux.
foo.h:
#ifndef FOO_H
#define FOO_H
void foo(void);
#endif
foo.c
#include "foo.h"
#include <stdio.h>
void foo(void)
{
// modified to verify the code was called
printf("This Hello World was called in C++ and written in C\n");
}
bar.cpp
extern "C" {
#include "foo.h" //a C header, so wrap it in extern "C"
}
int main() {
foo();
return(0);
}
Makefile
# -*- MakeFile -*-
# dont forget to use tabs, not spaces for indents
# to use simple copy this file in the same directory and type 'make'
myfoobar: bar.o foo.o
g++ -o myfoobar foo.o bar.o
bar.o: bar.cpp
g++ -c -o bar.o bar.cpp
foo.o: foo.c
gcc -c -o foo.o foo.c

Calling C++ functions from C file

I am quite new to C and C++. But I have some C++ functions which I need to call them from C. I made an example of what I need to do
main.c:
#include "example.h"
#include <stdio.h>
int main(){
helloWorld();
return 0;
}
example.h:
#ifndef HEADER_FILE
#define HEADER_FILE
#ifdef __cplusplus
extern "C" {
#endif
void helloWorld();
#ifdef __cplusplus
}
#endif
#endif
example.cpp:
#include <iostream.h>
void helloWorld(){
printf("hello from CPP");
}
It just doesn't work. I still receive the error of undefined reference to _helloWorld in my main.c. Where is the the problem?
Short answer:
example.cpp should include example.h.
Longer answer:
When you declare a function in C++, it has C++ linkage and calling conventions. (In practice the most important feature of this is name mangling - the process by which a C++ compiler alters the name of a symbol so that you can have functions with the same name that vary in parameter types.) extern "C" (present in your header file) is your way around it - it specifies that this is a C function, callable from C code, eg. not mangled.
You have extern "C" in your header file, which is a good start, but your C++ file is not including it and does not have extern "C" in the declaration, so it doesn't know to compile it as a C function.
the extern "C" tells C++ that the declared function has to use the C ABI (Application Binary interface), hence, whether the language is C or C++, your void HelloWorld() is always seen externally as it is C.
But you implemented it in the cpp file like it is a C++ one, C is not aware of.
You have to make the prototype of HelloWorld coherent for both C and C++, so the cpp file should declare it as extern "C" void Helloworld() { /*your code here*/ }, or simply, #include "example.h" from example.cpp, so that, before implementing it, the compiler already knows it has to follow the C convention.

Including functions with extern C linkage in library

I have included some C functions with extern c linkage in c++ code. E.g.
// File Y.cpp:
extern C {
void fnA(void) { }
void fnB(void* a, void* b) { }
}
class test {
....
};
// end of file
File Y is under module Mod. While building library libMod-O.a for module Mod, I don't see the functions under extern block included, unless Y.h is included in some other file (Mod.cpp) and the class test is used. So unless I create an object of test class in Mod.cpp, I do not see the extern functions (fnA, fnB) in the libMod-O.a, even through Y.cpp is compiled during build of libMod-O.a. The result of this is that linker error happens as another module uses fnA, fnB.
I do not see the connection between the extern functions fnA and fnB being included and usage of class test in Mod.cpp. Is this expected or is there a better way to define this?
You mean extern "C" of course.
You need to have a clean separation between your C code and your C++ code.
In YourCCode.h:
#ifdef __cplusplus
extern "C" {
#endif
void fnA(void);
void fnB(void* a, void* b);
#ifdef __cplusplus
}
#endif
In YourCCode.c:
void fnA(void) {}
void fnB(void* a, void* b) {}
Make sure your compiler compiles YourCCode.c as C, not as C++.
In your C++ code
#include "YourCCode.h"
fnA();
// etc.
you might have a link order problem where the files that use fnA come after the link of libMod-O.a but where Mod.cpp with object test comes before libMod-O.a so the obj file is pulled in before fnA/fnB are needed later. the gnu linker is a single pass linker by default.