views:

187

answers:

5

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 ??

+1  A: 

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");
Evgeny
Note that __cdecl is Microsoft specific.
Billy ONeal
@Billy ONeal: So is `GetProcAddress` and Visual Studio.
dreamlax
GetProcAddress is not Microsoft specific, but it is Windows specific. I can use GetProcAddress with MinGW for example, but not __cdecl.
Billy ONeal
And for the record I +1'd, I just thought that was an important note.
Billy ONeal
A: 

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).

wickedchicken
+4  A: 

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.

Paul Keister
A: 

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".

Igor Zevaka
A: 

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.

Chris Becke