-4

I need to make a wrapper for a C header, in such a way that none of the functions from that header can be visible outside this wrapper.

The first thing that came to my mind was to use a namespace in the include, but it didn't work, as expected, due to C++ mangling, like so:

namespace wrap {
    extern "C" {
        #include<a/b/c_header.h>
}};

This will give me errors like: cannot convert 'wrap::some_type*' to 'some_type*' for argument # from __some_inner_function, which I find very annoying because both types are actually the same.

This header has hundreds of functions which I'm currently using in my code, so wrapping one by one might not be feasible, in particular because it is not something so trivial to be solved with a few sed's.

I'm afraid that this has no solution, and that I would simply have to accept that all functions from those headers will have global scope.

I wondered if I could make some fancy macros to help me on this, but I couldn't come up with anything.

Kira
  • 463
  • 4
  • 12

2 Answers2

1

The only way to hide a C function and expose an equivalent C++ function is to declare the C++ function, and have it call the C function.

extern "C" int c_function (int);

namespace wrap {
    int c_function (int arg) {
        return ::c_function(arg);
    }
}

If your C interface uses variable arguments, you may want to use a C++ template to wrap the call instead. If C++ 11 is not available to you, then it may not be possible to properly wrap that interface unless the C interface provides an alternate version of the function that accepts a va_list parameter.

extern "C" int c_function_var_args (int, ...);
extern "C" int c_function_va_list (int, va_list);

namespace wrap {
#if defined(HAVE_VARIADIC_TEMPLATES)
    template <typename... Types>
    int c_function_var_args (int arg, Types... rest_args) {
        return ::c_function_var_args(arg, rest_args...);
    }
#else
    int c_function_var_args (int arg, ...) {
        va_list ap;
        va_start(ap, arg);
        int r = ::c_function_va_list(arg, ap);
        va_end(ap);
        return r;
    }
#endif
}
jxh
  • 69,070
  • 8
  • 110
  • 193
0

The attempt to wrap a header using

namespace wrap {
    extern "C" {
        #include<a/b/c_header.h>
}};

is pretty useless, since extern "C" {} forces c-style name mangling for everything declared inside that scope.

You should drop the extern "C" {} stuff, to have c++ compliant symbol resolution for the declarations appearing inside the namespace.

Also see this Q&A for detailed explanation what extern "C" actually does.

Community
  • 1
  • 1
πάντα ῥεῖ
  • 1
  • 13
  • 116
  • 190
  • Is it so useless that it's namespace std { extern "C" strlen(const char *s); } ? Note that if this is a C header, it won't work without the extern "C" – Joshua Jun 28 '16 at 01:14
  • @Joshua `extern "C"` actually prevents adoption to a c++ namespace, but forces c-style function name mangling. – πάντα ῥεῖ Jun 28 '16 at 01:18