I want to define two functions with the same name in different header files, such that:
A) Each function can be called by a C++ program (using namespaces to avoid conflicts).
B) The functions can be used with Python ctypes
, which requires extern "C"
to prevent name mangling.
While A
is easily achievable using namespaces, B
requires extern "C"
, which discards the C++ namespace information, resulting in a redefinition error during compilation.
one.h
namespace one{
extern "C" void free(void *ptr);
}
two.h
namespace two{
extern "C" void free(void *ptr);
}
This works fine in C++ code using namespaces to differentiate between one::free()
and two::free()
. However, when I add extern "C"
to make the functions accessible from Python ctypes
, I get a compiler error due to redefinition.
I know I could use unique function names for each function, but I’m looking for a way to use the same function name for both C++ and Python ctypes
.
Is there a way to have the same function name in different header files, accessible by both Python ctypes
and C++ library calls, without causing this redefinition error?
To use lib1::func
and lib2::func
you must have the C++ versions mangled (no extern "C"
).
You can have a mangled C++ symbol with the namespace and an extern "C" unmangled symbol with the same name, then you can make the C function call the C++ one, the compiler should inline the C++ one inside the C version. (unfortunately symbol renaming doesn't work with mangled C++ functions)
// lib1.h
namespace lib1
{
void func(void* ptr);
}
// lib1.cpp
void lib1::func(void* ptr)
{
std::cout << "lib1 func called\n";
}
extern "C" void func(void* ptr);
extern "C" void func(void* ptr)
{
lib1::func(ptr);
}
Note that the extern "C"
one is in the .cpp
file not the header, it is only exported from the shared object, but we don't allow anyone to use it in the C++ land.
Repeating the same thing in lib2
then in C++ land you can use lib1::func
or lib2::func
without any issues, and using ctypes you can use lib1.func
or lib2.func
without issues. (because python loads shared objects with RTLD_LOCAL
).
The only limitation is that you cannot statically link lib1
and lib2
otherwise you will get repeated symbol error from the unmangled func
(you can get around this by only defining the unmangled symbol in the shared objects), also calling ::func
from C++ is undefined behavior (ODR violation) and will likely depend on where it is used.
Note: C already has a global free
so avoid using this name as it will clash with the global free, and will fail to compile.