This question already has answers here:
C linkage for function pointer passed to C library
(2 answers)
Closed 9 years ago.
Are pointers to (non-member) C++ functions compatible between C++ and C ?
Given e.g. C code that does
void doit(void (*cb)(int i))
{
cb(100);
}
Can the do_it function (which would have C linkage) be called from C++ code
with a C++ function pointer e.g.:
namespace {
void my_function(int i) {
//...
}
void other_function() {
doit(my_function);
}
};
where my_function is a non-member function, or a static member function ?
I suppose this must mean the calling convention is the same for C and C++ code for that to work
- is that guaranteed ?
Or does the C++ code need C linkage to the function passed as a pointer to doit,
e.g.
namespace {
extern "C" {
void my_function(int i) {
//...
}
}
void other_function() {
doit(my_function);
}
};
As far as I'm aware (and for common types of processor architectures), as long as the function is a "free function" or "static member function", it will have the same calling convention in C++ and C. It is only naming convention that changes with that type of function. When you pass a function as a parameter to the another function, it is not using the name of the function (beyond the immediate compilation, that is) to determine which function it is - it's just an address of a function at that point.
So it should be perfectly fine to do your first option.
Technically, the function must have extern "C" linkage in order to be passed as a pointer to a function expecting a C-linkage function pointer. With that said, the compilers I've worked with have no problem accepting global functions and static member functions without explicit C linkage.
Note, however, that extern "C" also disables name mangling. This means that notwithstanding your anonymous namespace, if you do explicitly specify extern "C", a function named my_function in a different translation unit may lead to a multiply defined symbol when linking.
You can if it isn't a class function of course.
Else you need to specifiy the classname in your pointer name.
Related
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.
The following C++ code compiles with Visual C++ and g++:
struct S
{
static void foo();
};
extern "C"
void S::foo() {}
struct T
{
static void foo();
};
extern "C"
void T::foo() {}
auto main() -> int
{
S().foo();
T().foo();
}
Is it valid?
If it's valid, since the implementation may be in a separate translation unit, does that imply that a static member function always has the same calling convention as a C function (and if not, how does it not imply that)?
C++11 7.5/4 "Linkage specifications"
A C language linkage is ignored in determining the language linkage of
the names of class members and the function type of class member
functions.
So your example is valid in the sense that it's not malformed or an error, but the extern "C" should have no effect on S::foo() or T::foo().
A static member function has the same calling convention as a C function. But, name mangling applies. So, even if you get away with declaring your static member as extern "C", the linker would probably not find it when you try to link it against the C code that calls that function.
What you can easily do is declare a wrapper/stub that calls the static member from a plain function. Also, you can assign the static member function's address to a plain function pointer.
No it is ignored, the problem is name mangling (function naming for linkage phase). So the trick is to define a C function and use your C++ static method as a stub to call it, like this:
struct S
{
static void foo();
};
extern "C" void S_foo_impl();
void S::foo() { S_foo_impl(); }
auto main() -> int
{
S::foo();
}
Of course, S_foo_impl should be defined in a external C module.
Consider the following function defined in a C library:
void f(void (*callback)(int)) { callback(0); }
which will be called from a C++11 program defining the callback() as below:
struct S {
static void S::callback(int) noexcept {}
};
f(&S::callback);
Most compiler would probably compiler the above without any warnings, but, my question is, if strictly speaking, I must declare the callback as (a free) extern "C" function to be totally compliant with C++11 standard.
Specifications as extern "C" are for control of the names of functions, variables etc. But in your case S::callback address is passed as the argument in runtime, so the name of the function is not relevant, and no specification is necessary.
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 { ... };.
I have just started learning C++. Can some explain the difference between the following C++ function prototypes?
void f(int n);
extern void f(int n);
static void f(int n);
The void and extern void versions are the same. They indicate that the function has external linkage (i.e. the definition of the function may be expected to come from some other C or C++ file). Static indicates that the function has internal linkage, and will exist only in the current C++ file.
You almost never see these specifiers applied to functions because 99.9% of the time you want the default extern behavior.
You may see the static or extern storage specifiers on global variables though, which is often done to reduce name conflicts with other files in the same project. This is a holdover from C; if you're using C++ this kind of thing should be done with an anonymous namespace instead of static.
This is more of a C-language question than a C++ one, but:
void f(int n);
Declares a function f that takes a single integer parameter.
extern void f(int n);
Declares a function f that takes a single integer parameter but exists in some other file. The compiler will trust that you have implemented the function somewhere. If the linker cannot find it, you will get a linker error.
static void f(int n);
Declares a function f that takes a single integer parameter. The static keyword makes this interesting. If this is in a .cpp file, the function will only be visible to that file. If it is in a .h file, every .cpp file that includes that header will create its own copy of that function that is only accessible to that implementation file.
The first two are the same thing. The third one gives f internal linkage, meaning that a different source file may use the name f to be something different.
The use of static as in that third example should not be used. Instead use an anonymous namespace:
namespace { // anonymous
void f(int n);
}
Both answers so far have deprecated the use of static functions. Why? What makes
namespace {
void f(int n);
}
superior to
static void f(int n);
? It's not simpler, it's not easier to understand...
Anonymous namespace is a more universal and cleaner solution, you can have functions, variables, classes in it. And static is way too overloaded, in some contexts meaning internal linkage, in others static lifetime.
There is one disadvantage of anonymous namespace though. Because of external linkage, the exported section of your object/library files will swell with all those long <unique namespace name>::<function> names which wouldn't be there is they were static.