better understanding of extern "C" functions - c++

I am just trying to further understand extern C functions.
According to my knowledge, an extern C function is always a function you are trying call from an application that has already been compiled. Either a executable, static or dynamic library.
extern "C"
{
HRESULT CreateDevice();
typedef HRESULT (*CREATEDEVICE)();
HRESULT ReleaseDevice();
typedef HRESULT (*RELEASEDEVICE)();
}
So my question is...
Is my understanding correct ??
Does it always have to be a C function pointer ??'
Why must you use a typedef for each function ??
I presume that when you use the GetProcAddress(). You are allocating memory on that particulars applications HEAP and not the one you are calling it from. Therefore you must release it from that heap as well ??

extern "C" has 2 implications. First, it declares that the symbolic names of the functions are not "name mangled" to support C++. Second, it tells the compiler that the function is called using the C calling convention rather than the PASCAL calling convention. The difference has to do with when the return address is pushed on the stack. Using the wrong calling convention will crash your app.
This declaration is for the compiler, not the linker. So the extern C function could exist in your own modules or in a binary library: the source of actual bytes for the function implementation are resolved by the linker. If the function signature is declared as a regular C++ function and not extern C, the compiler will mangle the symbolic name to encode type information from the function signature. This will make it incompatible with object code generated by other C++ compilers. Therefore creating an extern C function allows you to share code between compilers in binary form. Note that you can't expose member functions this way, only old-style C functions.

It doesn't have to be a function pointer. You can specify the function declaration normally and prefix it with extern "C", as shown in some Microsoft examples.
If you use GetProcAddress() you are not allocating any memory. You simply get the memory address of the function inside the DLL that has already been loaded into memory (with LoadLibrary(), presumably).
Even when using function pointers (such as those returned by GetProcAddress) you don't have to use typedef, it's just that the code looks pretty ugly without it. It's always hard to figure out what to write as well. I think it would be something like:
void (*pReleaseDevice)() = (void (__cdecl *)(void))GetProcAddress(hInstance, "ReleaseDevice");

extern "C" {} is a C++ convention to declare that the enclosed functions are C functions -- not C++ functions. C++ has a slightly different naming convention which conflicts with C. If you have a library written in C and want to use it in a C++ program, you have to use extern "C" {} to let the compiler know these are C functions. If the library was written in C++ I believe the extern "C" {} will cause an error.
Note that extern has multiple meanings -- this specific case is a C++ convention and is unrelated to different uses of extern. For example,
extern int count;
has a completely different meaning than extern "C" {}.
The typedef is separate from the extern "C" {} issue. typedefs let you create aliases for common types that make more sense. For example, declaring structs is often a verbose process. I can use a typedef to shorten it:
struct mystruct {int a; int b};
typedef struct mystruct returncode;
// I can now declare a variable as type 'returncode'
returncode a;
Thus, in your example the HRESULT is really an alias for (*CREATEDEVICE)() although I believe you have to put it before the function (and not after).

One important aspect of specifying extern "C" linkage is that the function names do not get mangled, which is the default for C++ names.
In order for your library's functions to be able to be loaded using GetProcAddress, you need to either add the function to the .def file, use __declspec(dllexport) or use extern "C".

To answer, in order:
extern "C" functions are used for interop with C from C++. Using them has the consequence that C code can call the function. As the windows API is a C API all functions are extern "C" to ensure that C and C++ code can make use of the API.
In order for c++ programs to interoperate with other languages, including C, as a convention , functions are exported using extern "C". Which is why a lot of dll code does this. It is not a technical requirement however.
So no, it does NOT have to be a C function pointer.
You don't have to use typedef's either.
The example code provided is from a header file that is publishing the exports of a DLL twice - Once as the set of extern "C" methods that are exported so that the dll can be statically linked. the other as a set of function pointer types, so that the dll can be dynamically loaded, and the function pointer types used with GetProcAddress.

Related

Difference extern"C" vs extern

Is there a difference whether I use the extern "C" specifier for the entire header, or specify extern for every function?
As far as I know, there is none, since only functions and variables can be linked externally, so when I use the extern specifier before every function prototype and extern variable, I have no need to use the global extern "C" declaration!?
Example A:
#ifdef __cplusplus
extern "C" {
#endif
void whatever(void);
#endif
Example B:
extern void whatever(void);
The presence of extern "C" in a C++ file allows to call the particular C++ function from a C client caller code.
What is the difference?
A long, long time ago C-compilers generated code and addressed functions by name only.
It didn't consider parameters.
When overloaded functions were introduced in C++, extern "C" was required to specify the same name for different functions. For example void f() and void f(int) are two different functions in C++.
The C++ compiler accomplished this via name-mangling. It adds some info to the function name related to the functions parameters.
extern "C" is a command to the compiler to "refer to the older style naming convention - without mangling".
There is a difference between those two things.
The first says "the functions in here should be compiled so as to be callable from C". C++ allows multiple functions to have the same name as long as they take different arguments. C does not. To achieve that, C++ includes argument type information in the compiled name of its functions. As a result a C compiler will not be able to find the functions. If you add an extern "C" then you instead get C behaviour, but you gain the ability to call those functions from C.
The latter says "this function exists in another compilation unit". Which means that a compiler should trust that the function with that signature exists but not worry about being unable to see it. It'll be there when you link, you promise. Declarations (contrasting with definitions) are extern by default since at least C99.

Is it possible for a C method not be able to be included in a C++ project?

I know I can include C methods inside a C++ project using the extern "C" thing. But lets us now suppose that I'm thinking in creating a C++ project that would use quite a lot of C methods coming from both libraries made by me as well as libraries made by other people/companies whose developing details and compilation specifications I'm simply not aware of.
Is it possible that some of this methods of C libraries, with unknown compilation and configuration details, could not be included in my C++ project with extern "C"? Or are all C methods necessarily 100% compatible with C++ code insofar extern "C" is used?
It's possible that some of the functions exported by C use names that collide with C++ keywords. You wouldn't be able to declare those using extern "C".
Functions exported by assembler could even use names that conflict with C keywords.
Those and functions declared static can still be called via function pointer, as long as the library gives you a way to get one.
Headers might not be parse-able in C++ mode for the same reasons -- things like the restrict keyword.
Other than naming issues, C++ has full support for the C calling convention. That's what extern "C" is all about.
C has constructs for interfaces that are not compatible with C++, in particular variable length arrays. In modern C you would write
void matMult(size_t n, size_t k, size_t m, double A[n][k], double B[k][m], double C[n][m]);
this interface can not be included as such in C++ compilation units.
Although rather unlikely, one possible issue that might arise with extern "C" in-place is when a function pointer declared extern "C" points to a C++ function that is not declared extern "C". See the last part of this page for more details.

Using dlsym in c++ without extern "C"

I have a system in which I give the user a function prototype and the user has to implement it. Now, I compile this file using g++ and load it dynamically using dlopen and dlsym to process it further. Now, I read here:
c++ dlopen mini-howto
that to load c++ functions we have to use extern "C" before the function. Now, the problem is, I do not want to show the user how things are working. I do not want to show the user extern "C" before the function.
Is there any way to avoid it?
You can use the mangled C++ name directly.
If you have e.g. a C++ function void my_plugin(int foo) , the C++ compiler will mangle that name.
Once you know the mangled function name, you can use dlopen() on that name.
e.g.
# nm libmyplugin.so |grep my_plugin
00000000 T _Z9my_plugini
So here our function is named _Z9my_plugini , and you could do
func = dlsym(handle, "_Z9my_plugini");
Traditionally different compilers could mangle the name in different ways, so this could be quite fragile, thoug these days most C++ compilers will aggree opon a standard way of mangling the names on a given platform.
However your users will be programmers, and they would normally have an understanding of exposing an entry to a dynamically loaded library as extern "C"
Since you are using C++, why don't you export only one (or two) functions that will simply return a pointer to some kind of pure virtual class, say IMyModule? The one (or two) exported extern "C" functions would be something similar to extern "C" IMyModule * create_instance_IMyModule(); (and extern "C" void delete_instance_IMyModule(IMyModule const *);).
Another alternative to extern "C" before each declaration is to use the block-style syntax:
extern "C" {
void my_callback();
int other_functionality( foo * );
}
Often the extern "C" { and closing brace } are wrapped in macros, which are conditional on the __cplusplus built-in macro, so the header can also be used from pure C. This also encapsulates the part you find objectionable.
In any case, I don't see what the big deal is. If the user can write in C++, they should be competent to enclose their C interface function prototypes in extern "C" when the library documentation tells them to.

When is "extern C " necessary in c++ in windows?

As we know that we can use c functions directly in c++, when is extern "C" necessary then?
If your function is implemented in a .c file, the .cpp files will need the extern "C" reference, or else they'd reference a mangled C++-style function name, and the link would fail.
It's also handy for exporting functions from DLLs so that they are exported with a non-mangled name.
It's necessary when a C++ function must be called by C code rather than C++ code.
Basically, when you want your C++ library to be backwards compatible.
There are two rather different uses for extern "C". One is to define a function in C++ that you should be able to call from C. I.e., you're writing code in C++, but it needs to interface with C code. In this case, you define the function as extern "C":
extern "C" {
int c_callable_func1() {}
int c_callable_func2() {}
}
When you do this, the interface of those functions must follow pretty much the same rules as they would in C as well (e.g., you can't overload the functions or use default values for any parameters).
The other (considerably more common) situation is that you have code written in C that you want to be able to call from C++. In this case, the function definitions remain exactly as before, but the functions need to be declared/prototyped as extern "C". In a typical case, you want to use a single header that can be #included in either a C or C++ file, so the structure looks something like this:
// myheader.h
#ifndef MY_HEADER_H_INCLUDED_
#define MY_HEADER_H_INCLUDED_
#ifdef __cplusplus
extern "C" {
#endif
int func1(void);
void func2(int);
#ifdef __cplusplus
}
#endif
#endif
So, a C++ compiler will see function declarations (and typedefs, etc.) surrounded by an extern "C" block, while a C compiler will see prototypes, not surrounded by something it doesn't recognize.
In the first case (C++ functions callable from C), you'll normally structure the header roughly the same way, so you can also call those functions from C++ if necessary (but at the interface, you still lose all extra features of C++ like function overloading).
As you know that c++ support function overloading, which define the same function or method many times with different parameters. To do this, the compiler has to add some part of symbols for each one ... for example, the compiler will change the function name foo in the following declaration
from
void foo(int f,char c);
to
foo#i&c
Unfortunately, C doesn't support this. All function names remain the same after compiling it. So, to call a c++ function from c, you have to know the exact name after the modification and I think it's hard and different from a compiler to another.
to work around this and be able call c++ function from c and stop the compiler from changing the names you have to use this keyword like
extern "C" {
void foo(int f,char c);
}
that's it !!!
Because the function signatures generated by C and C++ compilers differ -- this sets up the C convention for C function even when using C++.

Why do you need "extern C" for C++ callbacks to C functions?

I find such examples in Boost code.
namespace boost {
namespace {
extern "C" void *thread_proxy(void *f)
{
....
}
} // anonymous
void thread::thread_start(...)
{
...
pthread_create(something,0,&thread_proxy,something_else);
...
}
} // boost
Why do you actually need this extern "C"?
It is clear that the thread_proxy function is private internal and I do not expect that it
would be mangled as "thread_proxy" because I actually do not need it mangled at all.
In fact, in all my code that I had written and that runs on many platforms, I never used extern "C" and this had worked as-is with normal functions.
Why is extern "C" added?
My problem is that extern "C" functions pollute the global namespace and they are not actually hidden as the author expects.
This is not a duplicate!
I'm not talking about mangling and external linkage. It is obvious in this code that external linkage is unwanted!
Answer: The calling conventions of C and C++ functions are not necessarily the same, so you need to create one with the C calling convention. See 7.5 (p4) of C++ standard.
It is clear that the thread_proxy function is private internal and I do not expect that it would be mangled as "thread_proxy" because I actually do not need it mangled at all.
Regardless, it's still going to be mangled. (Had it not been extern "C") That's just how the compiler works. I agree it's conceivable a compiler could say "this doesn't necessarily need to be mangled", but the standard says nothing on it. That said, mangling doesn't come into play here, as we aren't trying to link to the function.
In fact, in all my code that I had written and that runs on many platforms, I never used extern "C" and this had worked as-is with normal functions.
Writing on different platforms has nothing to do with extern "C". I expect all standard C++ code to work on all platforms that have a standard C++ compliant compiler.
extern "C" has to do with interfacing with C, which pthread is a library of. Not only does it not mangle the name, it makes sure it's callable with the C calling convention. It's the calling convention that needs to be guaranteed, and because we can't assume we are running on a certain compiler, platform, or architecture, the best way to try and do that is with the functionality given to us: extern "C".
My problem is that extern "C" functions pollute the global namespace and they are not actually hidden as the author expects.
There's nothing polluting about the above code. It's in an unnamed namespace, and not accessible outside the translation unit.
extern "C" linkage does not necessarily mean that only name mangling is suppressed. In fact, there may be a compiler which treats extern "C" as a different calling convention.
The standard leaves this completely open as implementation-defined semantics.
The question is valid - although the function is being passed to a C library, that C library is not linking to the C++ code at all. It is only given the address of the function, so it has no interest at all in the name of the function.
The point is that extern "C" is the closest thing there is to a cross-platform way of telling the compiler to make the function use the standard C calling convention on that platform (i.e. exactly how parameters and return values should be passed on the stack).
It is unfortunate that it also has the side-effect of creating an extern linker symbol at the global level. But this could be mitigated by using a name like boost_detail_thread_proxy instead.
It's being used to make the function use whatever the compiler understands by the C calling convention while avoiding compiler specific keywords such as __cdecl.
That's all there is to it. It's got absolutely nothing to do with name mangling, namespaces or any of the other weird answers here (as you already knew when you asked).
Probably because you are interfacing a plain C library -- pthreads.
Since C and C++ are not guaranteed to have the same calling convention, you need to declare the callback function as extern "C" in order to pass it into the pthread_create C function.
The thread_proxy function above has external linkage (i.e. is visible outside its translation unit) because namespaces have no impact on extern "C" functions -- even anonymous namespaces. Instead, to give the thread_proxy function internal linkage, you need to declare it as static:
namespace boost {
namespace {
extern "C" {
static void *thread_proxy(void *f)
{
....
}
} // extern "C"
} // anonymous
...
} // boost
[Edit] Note that boost has incorporated this change. See https://svn.boost.org/trac/boost/ticket/5170.