Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I call C++ functions from C?

Tags:

c++

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. Thank you!

like image 712
Sharon Avatar asked Dec 06 '22 08:12

Sharon


2 Answers

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.

like image 64
Mestkon Avatar answered Dec 23 '22 11:12

Mestkon


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.

like image 32
cmaster - reinstate monica Avatar answered Dec 23 '22 12:12

cmaster - reinstate monica