How do you call a templated C++ free function from C?
Asked Answered
T

2

7

I want to pass the pointer of an instance of a function template to a C function as callback. It's obviously impossible to declare the template as 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?

Threewheeler answered 8/3, 2014 at 17:34 Comment(4)
Research "name mangling".Premaxilla
@ThomasMatthews: The OP seems to be fully aware of name mangling. The calling conventions seem to be the primary concern here.Crural
Related: https://mcmap.net/q/1480498/-assigning-pointer-to-function-with-c-linkage-to-pointer-to-function-with-c-linkage-and-vice-versa/951890Trinia
What platform are you on? On x64 there is only one calling convention. It differs between Unix-like and Microsoft, but within one OS it's just one calling convention.Gardie
F
4

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.

Frowst answered 8/3, 2014 at 17:47 Comment(0)
H
7

It's a bad idea to export C++ methods or template functions directly for a C library. In a C++ codebase I usually put the C bindings into a dedicated .cpp + .h file pair - the header file has to use an extern "C" block and C compatible function declarations. In the accompanying .cpp file you implement the C functions and since it's a .cpp file you can access C++ features (templates, classes, C++ functions, ...).

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)
{
    // We can use C++ features because the implementation is in a .cpp file.
    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);
}
Hystero answered 8/3, 2014 at 18:43 Comment(0)
F
4

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.

Frowst answered 8/3, 2014 at 17:47 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.