Reputation: 3919
I'm writing a C program (myapp) which needs to use a particular API; the API is written in C++. I've worked with C and C++, but never both at once, and I'm getting confused.
So, the API provides the following directory, which I've placed in a folder called include, at the same level as my makefile:
libmyapi.a
api/api.h
My main source file is src/myapp.c, and it includes the API using #include "api/api.h"
.
My make command is (plus some flags, which I haven't listed because I don't think they're relevant here):
gcc -Linclude -lmyapi -Iinclude src/myapp.c -o lib/myapp.sp -lrt
The problem I'm having is that the api.h file contains references to namespaces etc. Eg at one point it has:
namespace MyAPI {
namespace API {
typedef SimpleProxyServer SimpleConnection;
}
}
and obviously the C compiler doesn't know what this means.
So, I assumed I'd need to compile using a C++ compiler, but then someone said I didn't, and I could just "wrap" the code in "extern 'C'", but I don't really understand. Having read around online, I'm not any further on.
Do I need to compile in C++ (ie using g++)?
Do I need to "wrap" the code, and what does that mean? Do I just do:
#ifdef __cplusplus
extern "C" {
namespace MyAPI {
namespace API {
typedef SimpleProxyServer SimpleConnection;
}
}
}
#endif
or do I just wrap the lines
namespace MyAPI {
namespace API {
and then their corresponding }}?
The header file calls other header files, so potentially I'll need to do this in quite a lot of places.
So far I've got errors and warnings with all the variations I've tried, but I don't know whether I'm doing the wrapping wrong, setting g++ compiler flags wrong, using the wrong compiler, or what! If I know the method to use, I can at least start debugging.
Upvotes: 5
Views: 1377
Reputation: 12668
You cannot. You can use C functions in your C++ program. But you cannot use C++ stuff from C. When C++ was invented, it allowed for compatibility and reuse of C functions, so it was written as a superset of C, allowing C++ to call all the C library functions.
But the reverse is not true. When C was invented, there was no C++ language defined.
The only way you can call C++ functions is to convert your whole project into a C++ one... you need to compile your C functions with a C++ compiler (or a C compiler if they are plain C) but for a C function to call a C++ function it must be compiled as C++. You should declare it with:
extern "C" {
void my_glue_func(type1 param1, type2 param2, ...)
{
/* ... */
}
} /* extern "C" */
and link the whole thing as a C++ program (calling the c++ linker)
This is because C doesn't know anything about function overloading, class initializacion, instance constructor calls, etc. So if you even can demangle the names of the C++ functions to be able to call them from C (you had better not to try this), they will probably run uninitialized, so your program may (most) probably crash.
If your main()
function happens to be a C function, then there's no problem. C++ was designed with this thing in mind, and so, main()
is declared implicitly as extern "C"
. :)
Upvotes: 0
Reputation: 4046
You can write a small C++ program that creates a C binding for the API.
Gvien this API:
namespace MyAPI {
namespace API {
typedef SimpleProxyServer SimpleConnection;
}
}
you can create c_api.h
#ifdef __cplusplus
extern "C" {
#endif
struct api_handle_t;
typedef struct api_handle_t* api_handle;
api_handle myapi_api_create();
void myapi_api_some_function_using_api(api_handle h);
void myapi_api_destroy(api_handle h);
#ifdef __cplusplus
}
#endif
and c_api.cpp
#include "c_api.h"
#include <myapi/api/stuff.hpp>
struct api_handle_t
{
MyAPI::API::SimpleConnection c;
};
api_handle myapi_api_create()
{
return new api_handle_t;
}
void myapi_api_some_function_using_api(api_handle h)
{
//implement using h
}
void myapi_api_destroy(api_handle h)
{
delete h;
}
compile that with a C++ compiler and include the c_api.h file in the C project and link to the library you created with the C++ compiler and the original library.
Upvotes: 8
Reputation: 40625
Basically, your C++ library needs to export a pure C API. That is, it must provide an interface that relies solely on typedef
, struct
, enum
, preprocessor directives/macros (and maybe a few things I forgot to mention, it must all be valid C code, though). Without such an interface, you cannot link C code with a C++ library.
The header of this pure C API needs to be compilable both with a C and a C++ compiler, however, when you compile it as C++, you must tell the C++ compiler that it is a C interface. That is why you need to wrap the entire API within
extern "C" {
//C API
}
when compiling as C++. However, that is not C code at all, so you must hide the extern "C"
from the C compiler. This is done by adding the preprocessor directives
#ifdef __cplusplus1
extern "C" {
#endif
//C API
#ifdef __cplusplus1
}
#endif
If you cannot change your libraries header, you need to create a wrapper API that offers this pure C API and calls through to the respective C++ code.
Upvotes: 6
Reputation: 238351
How do I call C++ functions from C?
By writing calling functions whose declarations are valid in the common subset of C and C++. And by declaring the functions with C language linkage in C++.
The problem I'm having is that the api.h file contains references to namespaces
Such header is not written in common subset of C and C++, and therefore it cannot be used from C. You need to write a header which is valid C in order to use it in C.
Do I need to compile in C++ (ie using g++)?
If you have function definitions written in C++, then you need to compile those C++ functions with a C++ compiler. If you have C functions calling those C++ functions, then you need to compile those C functions with C compiler.
A minimal example:
// C++
#include <iostream>
extern "C" void function_in_cpp() {
std::cout << "Greetings from C++\n";
}
// C
void function_in_cpp(void);
void function_in_c(void) {
function_in_cpp();
}
Upvotes: 3