Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Call C++ nonmember function from C

Tags:

c++

I want to pass the pointer of an instance of a template function to a C function as callback. And It's obviously impossible to declare the template in extern "C".

Is it guaranteed that C++ uses the same calling convention with C for nonmember function? And is there any other effect of declaring a function in extern "C" besides it prevents incompatible name mangling?

like image 611
Sherwood Wang Avatar asked Mar 08 '14 17:03

Sherwood Wang


2 Answers

Its a bad idea to export C++ methods or template functions directly for a C library. If I have a C++ program then I usually put the C bindings into its separate .cpp + .h file pair and I surround the header file with and extern "C" block and I use only C compatible function declarations there. In the accompanying .cpp file you implement the functions and since its a .cpp file you can access C++ features (templates, classes, ...) in the actual implementation of the binding functions even if their signature is C compatible using C-friendly types.

In your case this case you should put a C binding function into this binder .cpp+.h file and from the implementation of that function you would be able to call an instance of the specified template function easily.

Simple stupid example:

CBindings.h:

// This is the header used by both C++ and C
#ifdef __cplusplus
extern "C" {
#endif

    // C compatible function declarations with C-friendly types.
    int int_from_string(const char* s);

#ifdef __cplusplus
}
#endif

CBindings.cpp:

#include "CBindings.h"
#include "WhateverCPPHeader.h"

int int_from_string(const char* s)
{
    // Since the implementation is in a .cpp file here we can do C++ish things.
    return FromString<int>(s);
}

WhateverCPPHeader.h:

// Somewhere in your C++ header files:
template <typename T>
T FromString(const std::string& s);

...
// Template specializations of FromString for several T types
...

Whatever.c:

#include "CBindings.h"
#include <stdio.h>

void my_c_func(void)
{
    int i = int_from_string("5");
    printf("%d\n", i);
}

This works on all platforms without problems and the cut between C/C++ is clearly separated into its own file.

like image 51
pasztorpisti Avatar answered Sep 30 '22 01:09

pasztorpisti


No. It's not guaranteed that it uses the same calling convention. You can use the calling convention modifiers like _stdcall, cdecl, pascal, etc. So you have to make sure that both sides know the same calling convention.

One way would be detecting the mangled name and define a proper prototype for the C function.

Consider changing the design; since you can't benefit from the template in C anyway, you can define a simple C++ function (defined extern "C") that calls the templated function.

like image 44
harper Avatar answered Sep 30 '22 02:09

harper