Question

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.

Was it helpful?

Solution

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.

OTHER TIPS

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.

Just encountered this situation... Not a pleasant experience.

The following was declared in one of my c files:

void unused_isr(void) {}
void ADC_IRQHandler(void)     __attribute__ ((weak, alias("unused_isr"))); 

Next somewhere in a cpp file I defined:

void ADC_IRQHandler(void) {                                                                                  
    ...
}

And I forgot to change the forward declaration to:

void ADC_IRQHandler(void);

It took me a while before I figured out I was doing everything right with respect to the AD conversion, but I failed to add "extern C" to the definition!

extern "C" void ADC_IRQHandler(void) {                                                                                  
    ...
}

Just my two cents why it might be useful in certain circumstances to have the habit to add it to the definition as well.

I think this needs to be clarified here, as I just had a similar issue and it took me a while to get this clear in my head, only Brooks Moses touched on this properly, and I think it needs to be stated more clearly ...

In summary the header may throw you off, all the compiler sees is the cpp file and if the header is not included with the extern "C" back into your cpp (which I commonly see), then the extern "C" will need to be in the cpp file somewhere (either in the definition, or another declaration) so the CXX compiler can know to make it with C linkage, the compiler does not care about the header, only the linker.

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 your compiler, this may or may not be defined. In your example, you also use 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.

See the comments below — Standard C++ requires the __cplusplus macro to be defined by the preprocessor.

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top