I want to provide a callback function for code written in Haskell (GHC). It uses GCC C-compiler-like function types to export/import functionality and interoperate at runtime with my code.
I have to provide a callback function, which in fact accept this pointer to the class and just call its method:
struct C
{
int f(int i) { ; }
static int f_callback(void * self, int i)
{
static_cast< C * >(self)->f(i);
}
};
Logically f_callback is a part of class C, so I placed it into the corresponding namespace scope.
But I worry about should I use extern "C" language specification (calling convention is matters here, not name mangling)? It is possible to declare and define extern "C" function in plain namespace, there are a couple of special rules for extern "C" functions defined with the same name in different namespaces, but there is no distinction between namespace of class scope and simple namespace one.
Is it possible to define static extern "C" function into class scope?
The external callback is by design not linked to a specific class.
Making it a static class member is perhaps nice according to the internals of your code, but it misrepresents the reality.
I'd therefore advise to make it an independent extern "C" function. This avoids misunderstanding and highlights assumptions (for example that self is assumed to be a C but could in reality be something else). If f() is public, all this will be very clean. If it would be private, you'd need to make your callback a friend and this tight coupling would be again highlighted.
The wrapper alternative would just add a redundant middleman to come to the same result.
Related
I have a DLL in pure C code. I would like to find a way to remove the library name prefix from the functions, classes, and structs; EX:
// lib.h
void foobar();
// lib.hpp
namespace foo {
bar();
}
I would like to avoid simply writing a wrapper for every function, since I'd have to write it for every time I want to add a function. Is there a better / more efficient way of writing this?
I started writing the wrapper idea, but there's a lot of functions to write this for. Void pointers worked a little better, but still had the same issue.
Unless you are worried about name conflicts between existing C++ function names and the C library, how about just using extern "C" (in your C++ code) and call it (from your C or C++ code). For example:
extern "C" void f(int); // apply to a single function
extern "C" { // or apply to a block of functions
int g(double);
double h(void);
};
void code(int i, double d)
{
f(i);
int ii = g(d);
double dd = h();
// ...
}
When code is enclosed within an extern āCā block, the C++ compiler ensures that the function names are un-mangled ā that the compiler emits a binary file with their names unchanged, as a C compiler would do.
This approach is commonly used to accommodate inter language linkage between C++ and C.
from this Reference
more from cppprefference.com
You could try this:
// lib.hpp
namespace foo {
constexpr auto bar = foobar;
}
This should create a function pointer, and because it is constexpr, it should get resolved at compile time, so no performance hit. Also, constexpr is implicitly inline, so that (or static) can be omitted from this definition.
This question already has an answer here:
extern "C" static void* function
(1 answer)
Closed 3 years ago.
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.
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.
I tried to create a function which is returning a vector in C++. But when it built to dll, the function name seems to be mangled.
I tried to use the extern C but the problem is return type vector cannot support if I use extern C
Error : C Linkage function cannot return C++ class std:: Vector
Below is the code I am using
class __declspec(dllexport) TestClass
{
public:
string sClassName;
string sName;
string sDescription;
};
extern "C"
{
vector<TestClass> __declspec(dllexport) GetInfoList();
}
We see it is not problem with easy solution. Here's an involved solution. Use a non-mangled name (extern "C") with GetProcAddress to access a special function in the higher level DLL. . Define all the functions you want to call, as virtuals, in an abstract base class. Call that function above to retrieve the pointer P to a lazily instantiated concrete class with virtuals overriden. Invoke desired method through the pointer P.
vector is C++ type and so cannot be directly given under extern "C". Give the function inside a class and export the class as C Type.
extern "C"
{
class __declspec(dllexport) ClassToExport
{
vector<TestClass> GetInfoList();
};
}
Now use this class object to axcess the function.
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.
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.
Would a wrapper be acceptable?
namespace foo {
int bar(int);
}
extern "C" int callable_from_c(int f) {
return foo::bar(f);
}
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.
I observed a function in a dll which has C linkage. This function returns class type. I am not sure how this is made possible as C doesn't understand class.
I wrote a sample dll and program myself and noted that the VC++ compiler shows a warning to this effect but doesn't stop you. The program is able to GetProcAddress of this function and call it to receive the returned object. The class definition was made available to program.
Furthermore, if I write a function with C linkage that returns a class type where this class is not even exported, the compiler doesn't issue any warning. The program can consume this function from the dll provided the class definition is made available to it.
Any thoughts on how this works? Is such a behavior compiler/platform specific?
You are misunderstanding the behavior of extern "C".
It only impacts the name of the function in the object file by preventing name mangling. It does not make a function neither "more C" or "less C++". The only additional limitation which extern "C" adds to a C++ function is that is shall not be overloaded.
It's possible for functions with C linkage to return objects that can't be expressed in C so long as they can be manipulated in C. According to my copy of Design & Evolution of C++ (section 11.3.3):
We considered several alternatives to the type-safe linkage schemes before deciding on the one actually added to the language [Stroustrup,1988]: ...
provide type-safe linkage only for functions that couldn't be C functions because they had types that couldn't be expressed in C. ...
A function declared to have C linkage still has C++ calling semantics. That is, the formal arguments must be declared, and the actual arguments must match under the C++ matching and ambiguity control rules. ... Had we provided special services for C, we would have been obliged to add an unbounded set of language calling conventions to C++ compilers [for linking to Pascal, Fortran, PL/I, etc.]. ...
Linkage, inter-language calls, and inter-language object passing are inherently difficult problems and have many implementation-dependent aspects. ... I expect we haven't heard the last of this matter.
That is, C++ linkage isn't based on whether the types involved are valid C types. That is an intentional design decision. It allows you to create a DLL compiled in C++ but that can be used from C via a header:
// in the header
struct Foo; // forward declaration
#ifdef __cplusplus
extern "C" {
#endif
struct Foo* create_foo();
void destroy_foo(struct Foo*);
void foo_bar(struct Foo*);
#ifdef __cplusplus
} // extern "C"
// now declare Foo
struct Foo {
void bar();
};
#endif
// in the implementation file
#include <iostream>
extern "C" {
Foo* create_foo()
{
return new Foo();
}
void destroy_foo(Foo* f)
{
delete f;
}
void foo_bar(Foo* f)
{
f->bar();
}
}
void Foo::bar()
{
std::cout << "Foo::bar() called\n";
}
Note the calls to new, delete and std::cout. These all require the C++ runtime. Therefore, the implementation file must be compiled with C++, but since the functions have C linkage, the header can be used from either C or C++.
So how do you get a Foo in C? In this case, you don't, because there's no way to fully declare it in the header in a way that C will understand. Instead, C only sees the forward declaration, which creates an incomplete type. C doesn't know how large an incomplete type is, so C functions can't create it or operate on them directly, but C does know how large a pointer to an incomplete type is, so C can operate on a pointer to an incomplete type. You can get much more creative and actually create POD types in C++ that you can operate on directly in C.
As long as you only use Foo*s in C, you don't have to actually define the Foo struct in C. It so happens that APR uses a similar design ("Creating an APR Type," I couldn't find a better link).
A class object is basically just a struct object, with some extra "hidden" members for the vtbl and so on.
However, I'm not sure what you mean by "the program can consume this function provided the class definition is made available to it". C would throw a compiler error on seeing class Blah { ... };.