Matt
Matt

Reputation: 22163

How can I implement in C a function declared in a C++ namespace?

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

Answers (3)

Luis Colorado
Luis Colorado

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

Tim Čas
Tim Čas

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

user590028
user590028

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

Related Questions