Sharon
Sharon

Reputation: 3919

How do I call C++ functions from C?

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

Answers (4)

Luis Colorado
Luis Colorado

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

Mestkon
Mestkon

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

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

eerorika
eerorika

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

Related Questions