Reputation: 22163
Let's say I have a C++ header file foo.hpp
:
namespace foo {
int bar(int);
}
I cannot use extern "C"
because it needs to only be accessible from the namespace foo
.
Is there a portable (or relatively portable) way to declare foo::bar
in a C file foo.c
so that it will link with anyone using foo::bar
from C++?
I know that on a particular system with a particular compiler, I can just find out how foo::bar
is mangled and do something like this in foo.c
:
int ZN3foo3barEi(int x) { /* ... */ }
But this is neither portable nor readable.
Upvotes: 2
Views: 118
Reputation: 12708
You are forced to your backup plan (to use a wrapper function) for the following reason: C++ supports overloading of functions, and by that reason you can have different implementations of bar
(with different fingerprints, even compatible) while you can have only one implementation in C. Which of the C++ possibilities would be matched for bar
in case you call them from C? What if you have bar(int)
and bar(long)
in C++ and you want to call bar(3)
from C?
The solution is to have one wrapper extern "C"
function that calls the appropiate non-C function. This function can be called from C and you'll get the desired results.
If you look, for example, at the identifier names that the linker manages, you'll see how the compiler mangles identifiers to cope at linking time with overloading. That does not happen if you declare a function extern "C"
in C++.
Another reason is that you don't have namespaces in C. The C function version must be visible at the global namespace level. You are not able to hide a C calling convention inside a namespace because it is callable from all the C code or you'll be violating the C calling conventions.
Upvotes: 0
Reputation: 10867
extern "C"
can be nested (in fact, that's how headers like <cstdio>
typically work!), so you can just do the following:
/* C++ code */
namespace foo {
extern "C" {
int bar(int);
}
}
After that, you just implement it in C as usual:
/* C code */
int bar(int x) {
return -x; /* or whatever */
}
Unfortunately, if there's a naming conflict (say, if you have both foo::bar
and baz::bar
), you won't be able to have them both, unless they're the same function.
Upvotes: 3
Reputation: 11748
Would a wrapper be acceptable?
namespace foo {
int bar(int);
}
extern "C" int callable_from_c(int f) {
return foo::bar(f);
}
Upvotes: 1