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
Related
I'd like to make a tool that automatically wraps C libraries in:
#ifdef __cplusplus
extern "C" {
#endif
But I'm confused by what exactly needs to be wrapped with extern "C", and what needn't be. Only functions? What about any (shock-horror) global variables? Anything else?
If I write a script that just finds all functions and wraps them with extern "C", is that enough?
And finally: if the library already wrapped its functions with extern "C" and then they're wrapped again, can I trust that nothing bad happens and it'll still work fine, or do I need to explicitly check for this?
It does not matter, because anything that does not need it (such as macros and comments) will be unaffected by it, so you can just wrap the entire header content - and that hardly requires a a "tool".
Also not this is not "modifying the library", just modifying the header.
Nested wrapping is benign - applying C linkage to something that already has it has no effect.
What extern "C" does is tell the C++ compiler not to apply name mangling to the specified symbol because it has C linkage and the corresponding name in the library has C linkage and is not name-mangled.
Name-mangling is the means by which C++ applies meta-data to a symbols in order to provide type information and parameter counts in order to support C++ features that require this information such as function overloading.
See this answer here which is partially related.
You'll basically just want to either:
Autowrap an include, i.e. extern "C" { #include <foo.h> }
Autowrap the C header files being included by the include (so, at the start of "foo.h" as opposed to the include statement itself)
As far as doubly-wrapped extern "C"s, I tested it with these files:
lib.h:
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
void printHWorld(void);
#ifdef __cplusplus
}
#endif
lib.c:
#include <stdlio.h>
#include <lib.h>
void printHWorld(void) {
printf("Hello, world!\n");
}
main.cpp:
#ifdef __cplusplus
extern "C" {
#endif
#include <lib.h>
#ifdef __cplusplus
}
#endif
int main(void) {
printHWorld();
return 0;
}
I then built it with the following commands:
gcc -Wall -O2 -I. -o lib.o -c lib.c
g++ -Wall -O2 -I. -o main.o -c main.cpp
g++ -o test main.o lib.o
And that worked just fine, so I don't think you need to worry about the double 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...
I am calling a C function from a header file I wrote in Qt written in Cpp. I keep getting a linking error when I try to compile my Qt Application.
here is the header file:
#ifndef GROUND_SERVER_H
#define GROUND_SERVER_H
#ifdef __cplusplus
extern "C" {
#endif
struct system_info{
char id[33];
};
/* Support function for the below function */
void Generate_Key(char*,char*,char*);
/* Runs the actual key generation as well as
moves the file to the respectful card or
USB drive inserted in the system that will
act as the user system key */
void run_key_generation(struct system_info*,char*,char*);
/* Function to run the server on a selected
port at which the medium that the server
is to listen on will be connected. */
void run_server(unsigned short);
void generate_id();
#ifdef __cplusplus
};
#endif
#endif
#include "foo.h" is only the textual inclusion of the contents of foo.h into the current compilation unit. If you implement a function in a different file, then you need to compile that file, too, and link the resulting object files to form an executable (or library).
This does also apply when mixing C and C++ (or most other compiled) code: You compile the source code files with the compiler suitable for the language they're written in, and finally link everything together.
So:
foo.h
#ifndef FOO_H
#define FOO_H 1
#ifdef __cplusplus
extern "C" {
#endif
int answer(void);
#ifdef __cplusplus
}
#endif
#endif
foo.c
int answer(void) {
return 42;
}
bar.cc
#include <iostream>
#include "foo.h"
int main(int argc, char ** argv) {
std::cout << "The answer is " << answer() << std::endl;
return 0;
}
To create an executable from these files, you need to:
gcc -c foo.c # Compile C file
g++ -c bar.cc # Compile C++ file
g++ -o foobar foo.o bar.o # Link
I tried to link a static library (compiled with gcc) to a c++ program and I got 'undefined reference'. I used gcc and g++ version 4.6.3 on a ubuntu 12.04 server machine. For example, here is the simple library file for factorial method:
mylib.h
#ifndef __MYLIB_H_
#define __MYLIB_H_
int factorial(int n);
#endif
mylib.c
#include "mylib.h"
int factorial(int n)
{
return ((n>=1)?(n*factorial(n-1)):1);
}
I created object for this mylib.c using gcc:
gcc -o mylib.o -c mylib.c
Again the static library was created from the object file using AR utility:
ar -cvq libfact.a mylib.o
I tested this library with a C program (test.c) and C++ program (test.cpp)
Both C and C++ program have the same body:
#include "mylib.h"
int main()
{
int fact = factorial(5);
return 0;
}
Assuming static library libfact.a is available in /home/test directory, I compiled my C program without any issues:
gcc test.c -L/home/test -lfact
However while testing C++ program, it threw a link error:
g++ test.cpp -L/home/test -lfact
test.cpp:(.text+0x2f): undefined reference to `factorial(int)'
collect2: ld returned 1 exit status
I even tried adding extern command in test.cpp:
extern int factorial(int n) //added just before the main () function
Still the same error.
Can someone tell me what I am wrong here?
Is there anything I missed while creating the static library?
Do I have to add anything in my test.cpp to make it work?
The problem is that you haven't told your C++ program that factorial is written in C. You need to change your test.h header file. Like this
#ifndef __MYLIB_H_
#define __MYLIB_H_
#ifdef __cplusplus
extern "C" {
#endif
int factorial(int n);
#ifdef __cplusplus
}
#endif
#endif
Now your header file should work for both C and C++ programs. See here for details.
BTW names containing a double underscore are reserved for the compliler (so are names starting with an underscore and a capital letter) so #ifndef __MYLIB_H_ is illegal strictly speaking. I would change to #ifndef MYLIB_H #define MYLIB_H
While the accepted answer is absolutely correct, I thought I'd just add an observation. Some editors have trouble with the open / close brace, and will indent the entire extern "C" scope in the header. If mylib.h is a key header for a library, you might consider:
#if defined (__cplusplus)
#define _MYLIB_INIT_DECL extern "C" {
#define _MYLIB_FINI_DECL }
#else
#define _MYLIB_INIT_DECL
#define _MYLIB_FINI_DECL
#endif
All other headers in mylib library, e.g., mylib_aux.h, can be of the form:
#ifndef _MYLIB_AUX_H
#define _MYLIB_AUX_H
#include <mylib.h>
_MYLIB_INIT_DECL
... header content ...
_MYLIB_FINI_DECL
#endif /* _MYLIB_AUX_H */
Obviously, the names I'm using are arbitrary, but for multiple library headers, this approach has been useful to me.
I have a problem. I wrote example code and I want to build it without the error:
main.cpp(.text+0x5): undefined reference to `test()'
Library
test1.c
#include <stdlib.h>
void test()
{
puts("DziaĆa");
}
test1.h
#ifndef TEST1_H
#define TEST1_H
extern void test();
#endif
makefile
all:
gcc -c ./src/test1.c -o ./lib/test1.o
ar rcs ./lib/libtest1.a ./lib/test1.o
Program
main.cpp
#include <test1.h>
int main()
{
test();
return 0;
}
makefile
all:
g++ -static -I../test1/include -L../test1/lib ./src/main.cpp -o ./build/MyApp -ltest1
What am I doing wrong?
You are compiling a C code function, but you are expecting to link a C++ function.
Because of 'type safe linkage', the function you provide is not the function that the C++ code calls.
Either in test1.h use:
#ifdef __cplusplus
extern "C" {
#endif
extern void test1(void);
#ifdef __cplusplus
}
#endif
Or:
Compile the function with the C++ compiler.
The C++ compiler will mangle the symbol names to provide type-safe linkage (a term which you should be able to search for via your preferred search engine).
The 'compiler' - actually the linker - is looking for a function with a C++ mangled name representing the C++ function with the signature 'void test1(void);'.
For example (but remember - different compilers deliberately mangle things differently), G++ 4.2.1 on MacOS X 10.6.2 generates a symbol '__Z5test1v' for the function; GCC generates a symbol '_test1'. Clearly, when the linker is looking for '__Z5test1v', the symbol '_test1' is not going to be used - it is not spelled the same. This is a good thing.
You can use 'nm -g' on the object file for the main program to see what it is looking for, and on the object file in the library to see what it is providing. And, given that the spellings are different, that is why the loader does not pick up the library function - it is looking for something with a different name.
You are calling a C function from a C++ function. The naming between the two is different (C++ mangles names to include parameter information).
Change the header file to look like this:
#ifdef __cplusplus
extern "C" {
#endif
extern void test();
#ifdef __cplusplus
}
#endif
This will tell the compiler that the function follows the C naming/calling convention.