Is extern "C" only required on the function declaration?
Asked Answered
O

6

41

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

Obeded answered 4/9, 2009 at 18:30 Comment(4)
Are you certain that you actually get the mangling of foo if you leave off the extern "C" in foo.c in the example code you show? Or was this just something that occurred in other more complicated code? I've quite often seen this problem as a symptom of forgetting to include foo.h in foo.c.Notice
@Brooks Moses: That's a great point. In my actual code, which is slightly more complex than this "foo" example, I am including the header in the "cpp" source file. What made me think that the compiler was mangling the name was this: If I do not include the 'extern "C"' on the function definition, then the compiler listing shows the external symbol, "foo_FPFPCc_v". When the 'extern "C"' is included, the listing shows the external symbol, "foo".Obeded
@Obeded - it might be interesting to experiment with what the compiler does with your simplified example. If it shows the same behavior, then you might want to send a note to the vendor. If it doesn't show the same, then you should track down what's going on in your real build, because that would indicate that the wrong header is being brought in (or something else is making the function declaration to be missed).Rhodesia
@Michael Burr - That's a good point that this could be a build issue (e.g. some other header is getting included, etc.). I'll give that a try, and if I learn anything new that might be useful to others, I'll post a comment here. Thanks!Obeded
R
42

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

Rhodesia answered 4/9, 2009 at 18:48 Comment(2)
@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.)Obeded
I thought that I was the only one who puts virtual on method overrides :-)Pavid
G
1

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.

Geometrize answered 4/9, 2009 at 19:8 Comment(1)
@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.Obeded
S
1

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.

Snapback answered 4/9, 2009 at 19:54 Comment(4)
@Snapback - 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.Obeded
The "__cplusplus" macro is required by the standard to be defined when compiling a C++ module - there's absolutely no issues with using it.Rhodesia
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).Rhodesia
@Michael Burr - I've always taken "__cplusplus" for granted, but I didn't realize it is required by the standard. Thanks for clarifying this.Obeded
R
1

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.

Rutherfurd answered 7/11, 2014 at 9:21 Comment(0)
K
1

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.

Kaiserism answered 21/1, 2015 at 4:4 Comment(0)
B
0

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.

Betoken answered 4/9, 2009 at 18:32 Comment(1)
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.Notice

© 2022 - 2024 — McMap. All rights reserved.