13

I'm trying to interface with a C library, which expects me to provide a pointer to a callback function.

As I understand it, according to the standard the callback must have C language linkage, due to possibly different calling convention. I can accomplish this by declaring my callback function as extern "C". However this has an undesirable side effect: exposing the function's unqualified and unmangled name to other translation units.

Is it possible to declare a function such that its name has internal linkage (not visible to other translation units), but which can be called from C via a pointer (has appropriate calling convention) using only standard C++?

If it's impossible to make it have internal linkage, is it at least possible to make it keep its C++ name mangling?

I tried:

  • Declaring it as static extern "C" void f(); which caused a compilation error to the effect that static and extern "C" cannot be used together.
  • Declaring it within an anonymous namespace as namespace { extern "C" void f(); } which turned out to have the same effect as regular namespace, exposing the unmangled unqualified name.
yuri kilochek
  • 12,709
  • 2
  • 32
  • 59
  • 3
    https://stackoverflow.com/questions/38447615/extern-c-static-void-function – Mat Jan 28 '20 at 12:47
  • 2
    No need to declare a function `extern "C"`. All that is needed is for the function that accepts a pointer to a function with appropriate types of arguments and return type. The function which accepts a pointer to a function gets no information about the name of the passed function - mangled or otherwise - from the caller. Obviously, the types have to be valid in C. I assume you aren't using any compiler-specific keywords or calling conventions. – Peter Jan 28 '20 at 12:48
  • 2
    FYI: [C/C++ Calling Conventions](https://scc.ustc.edu.cn/zlsc/sugon/intel/compiler_c/main_cls/bldaps_cls/common/bldaps_calling_conv.htm) – Scheff's Cat Jan 28 '20 at 12:49
  • 3
    @Peter What about [this comment](https://stackoverflow.com/questions/38447615/extern-c-static-void-function#comment64301468_38447828) on the [answer](https://stackoverflow.com/a/38447828/5264491) to the [linked question](https://stackoverflow.com/questions/38447615/extern-c-static-void-function)? That claims that the calling convention may differ between C and C++ functions, so it seems safer to declare the function within `extern "C" {` `}`. – Ian Abbott Jan 28 '20 at 12:59
  • @Mat The suggested solution seems to work fine for clang and msvc, but [not for gcc](https://godbolt.org/z/bd3fhi). GCC bug? – yuri kilochek Jan 28 '20 at 13:21
  • @AdrianMole see above. – yuri kilochek Jan 28 '20 at 13:21
  • `Is it possible to declare a function such that its name has internal linkage (not visible to other translation units), but which can be called from C via a pointer (has appropriate calling convention) using only standard C++?` I do not understand that. Just create the pointer `extern "C" void (*f)(void);` and call it from C. Maybe, rather then explaining what you want to have, you could _show_ the code you are trying to implement. – KamilCuk Jan 28 '20 at 13:45
  • @KamilCuk Okay. Given `extern "C" void call(void (*)());` implemented in C that calls its argument. I want to declare a function `f` such that `call(f);` is well-defined. I believe this misses a lot of nuance though. – yuri kilochek Jan 28 '20 at 14:16
  • 1
    @KamilCuk Not guaranteed to work on all platforms. There is some discussion on it here: https://stackoverflow.com/questions/36941866/what-kinds-of-c-functions-can-be-placed-in-a-c-function-pointer – th33lf Jan 28 '20 at 14:28

1 Answers1

5
extern "C" {

static int my_callback(int a)
{
    return a + 1;
}

}

The above code compiles perfectly fine. The symbol would not be visible outside the translation unit and you can invoke the function through a pointer.

You can pass this function to your C code from within this file and rest assured that it doesn't pollute your global namespace.

th33lf
  • 2,177
  • 11
  • 15
  • [And yet](https://godbolt.org/z/bd3fhi). – yuri kilochek Jan 28 '20 at 13:28
  • 2
    @yurikilochek Can you please elaborate? – th33lf Jan 28 '20 at 13:30
  • 1
    I'll drop by and quote [cppreference language linkage](https://en.cppreference.com/w/cpp/language/language_linkage) `When two functions with the same unqualified name are declared in different namespaces, and both have "C" language linkage, the declarations refer to the same function`. Guessing from the godbolt link, maybe this is what is confusing OP. – KamilCuk Jan 28 '20 at 13:33
  • The code at the link demonstrates calling the supposedly internal function via its unqualified unmangled name, proving that the suggested solution does not in fact make it internal, at least on gcc. – yuri kilochek Jan 28 '20 at 13:37
  • Please read the comment and link quoted above by @KamilCuk. Namespaces do not count when using C linkage. And in this case, internal means that the function would be hidden _outside_ the translation unit in which it is declared. – th33lf Jan 28 '20 at 13:38
  • 3
    Try calling it from a different translation unit. I tried it myself and get an undefined reference error which means this solution works. – Kevin Jan 28 '20 at 13:39
  • @KamilCuk that either refers to the case without `static`, which is fine but irrelevant, or is true regardless of `static`, which would mean that declaring a function without any externally visible name but with C calling convention is impossible. Which is it? – yuri kilochek Jan 28 '20 at 13:42
  • 1
    That refers to all cases. I don't understand. The function there has internal linkage and C calling convention which proves it possible. – KamilCuk Jan 28 '20 at 13:43
  • @yurikilochek There is no such thing as "unmangled name" in C++. – n. m. could be an AI Jan 28 '20 at 13:47
  • @Kevin So it does, thanks. It's pretty bizarre. – yuri kilochek Jan 28 '20 at 13:50
  • @n.'pronouns'm. There is such a thing in virtually every implementation though. You know perfectly well what I mean. – yuri kilochek Jan 28 '20 at 13:52
  • @yurikilochek No, I don't. I really truly don't. I have no idea why I should ever think about talking in terms of an infinite number of subtly different and incompatible implementations. The standard says everything there is to be said, and there is no word about mangling in it. – n. m. could be an AI Jan 28 '20 at 13:58
  • @KamilCuk I was confused by the ability to link to a symbol that should not exist, but does. I assumed there exists a single global namespace (in the general, non-C++-specific sense) for exported symbols, and that `extern "C"` declarations directly (without mangling) refer to symbols form it. Since `ns::f` is `static`, it should not have produced an entry there, and so `::f` should have remained undefined. Clang and msvc seem to agree with this reasoning, gcc does not. – yuri kilochek Jan 28 '20 at 14:02
  • 2
    @yurikilochek still, your `f` function won't be accessible from another file, so you can put it and and the c++ function referring it in a separate file and call it a day. I think that here it's gcc which is doing the right thing according to the standard. –  Jan 28 '20 at 14:44