tags:

views:

517

answers:

4

I wrote a C++ function that I need to call from a C program. To make it callable from C, I specified extern "C" on the function declaration. I then compiled the C++ code, but the compiler (Dignus Systems/C++) generated a mangled name for the function. So, it apparently did not honor the extern "C".

To resolve this, I added extern "C" to the function definition. After this, the compiler generated a function name that is callable from C.

Technically, the extern "C" only needs to be specified on the function declaration. Is this right? (The C++ FAQ Lite has a good example of this.) Should you also specify it on the function definition?

Here's an example to demonstrate this:

/* ---------- */
/* "foo.h"    */
/* ---------- */

#ifdef __cplusplus
extern "C" {
#endif

/* Function declaration */
void foo(int);

#ifdef __cplusplus
}
#endif

/* ---------- */
/* "foo.cpp"  */
/* ---------- */

#include "foo.h"

/* Function definition */
extern "C"               // <---- Is this needed?
void foo(int i) {
  // do something...
}

My issue may be the result of incorrectly coding something, or I may have found a compiler bug. In any case, I wanted to consult stackoverflow to make sure I know which is technically the "right" way.

Thanks so much in advance!

A: 

It should be around both. The compiler needs to know to use the C symbol name and calling conventions when compiling the call sites (which may only see a declaration), and the compiler also needs to know to generate the C symbol name and use the C calling conventions when compiling the function definition itself (which may not see any other declarations).

Now, if you have an extern-C declaration that is visible from the translation unit in which the definition exists, you may be able to get away with leaving off the extern-C from the definition, but I don't know that for sure.

Tyler McHenry
This is incorrect in the case as described, where foo.h is included in foo.c, and "get away with" is misleading for using behavior required by the standard. If one includes foo.h in foo.c -- as one should always be doing anyway, so that the compiler can check that the declaration is actually accurate! -- then there is no need (other than perhaps clarity to readers) -- to put extern "C" on the definition within foo.c.
Brooks Moses
+7  A: 

The 'extern "C"' should not be required on the function defintion as long as the declaration has it and is already seen in the compilation of the defintion. The standard specifically states (7.5/5 Linkage specifications):

A function can be declared without a linkage specification after an explicit linkage specification has been seen; the linkage explicitly specified in the earlier declaration is not affected by such a function declaration.

However, I generally do put the 'extern "C"' on the defintion as well, because it is in fact a function with extern "C" linkage. A lot of people hate when unnecessary, redundant stuff is on declarations (like putting virtual on method overrides), but I'm not one of them.

Michael Burr
@Michael Burr - Thanks for your response. It sounds like the 'extern "C"' is not required on the definition as long as it is specified on a previous declaration. Like you mentioned, I may go ahead and specify it in both places, however. (In fact, I may need to unless I figure out that my problem is something other than a compiler bug. If it does look like a compiler bug, then I'll report it to the vendor so they can look into it.)
bporter
+1  A: 

Edit:
Seems like I had misunderstood the question. Anyways, I tried:


// foo.cpp
/* Function definition */

#include "foo.h"

void foo(int i) {
 //do stuff
}
void test(int i)
{
// do stuff
}

// foo.h
#ifdef __cplusplus
extern "C" {
#endif

/* Function declaration */
void foo(int);

#ifdef __cplusplus
}
#endif

void test(int);

Using command nm to view the symbols from the compiled file:


linuxuser$ nm foo.o
00000006 T _Z4testi
         U __gxx_personality_v0
00000000 T foo

This clearly suggests that the name of function declared as extern "C" is not mangled and the extern "C" keyword is not required at definition.
Had it required every C library code written without extern "C" would have been unusable in C++ programs.

Neeraj
@Neeraj - Thanks for your example. This is what I expected to see in my case as well. It appears my compiler mangles the "foo" function name unless I specify 'extern "C"' on the declaration and the definition. I think you and some of the other posters are correct that the 'extern "C"' is not required on the definition as long as it is specified on a previous declaration.
bporter
A: 

The extern "C" around the definition is not required. You can get away with just putting it around the declaration. One note in your example...

#ifdef __cplusplus
extern "C" {
#endif

/* Function declaration */
void foo(int);

#ifdef __cplusplus
}
#endif

Your code is looking for the preprocessor macro "__cplusplus".

While it's commonly implemented, depending on you compiler... this may or may not be defined. In your example, you also extern "C" around the declaration, but there you are not checking for the "__cplusplus" macro which is why I suspect it worked once you did that.

whitej
@whitej - The "__cplusplus" macro happens to be defined by my particular compiler, but you're right that it is not "standard". Also, I use this macro in the header because this is where I declare the function (and it is where most people would look to learn about the interface), and it allows me to include the header in both C and C++ files. C compilers do not support 'extern "C"', and so this macro inserts the 'extern "C"' only when it is appropriate. Note that the macro is not needed in "foo.cpp" if 'extern "C"' is specified, because "foo.cpp" will always be compiled by a C++ compiler.
bporter
The "`__cplusplus`" macro is required by the standard to be defined when compiling a C++ module - there's absolutely no issues with using it.
Michael Burr
And while the "`__cplusplus`" is often required in headers (since they might be included by C or C++ modules), it's usually not necessary in .c or .cpp files since they are typically designed to be compiled as C or C++, but not both (there are exceptions, of course, but usually not).
Michael Burr
@Michael Burr - I've always taken "__cplusplus" for granted, but I didn't realize it is required by the standard. Thanks for clarifying this.
bporter