简体   繁体   English

仅在函数声明中需要extern“ C”吗?

[英]Is extern “C” only required on the function declaration?

I wrote a C++ function that I need to call from a C program. 我写了一个C ++函数,需要从C程序中调用。 To make it callable from C, I specified extern "C" on the function declaration . 为了使其可以从C调用,我在函数声明中指定了extern "C" I then compiled the C++ code, but the compiler (Dignus Systems/C++) generated a mangled name for the function. 然后,我编译了C ++代码,但是编译器(Dignus Systems / C ++)为该函数生成了错误的名称 So, it apparently did not honor the extern "C" . 因此,它显然不尊重extern "C"

To resolve this, I added extern "C" to the function definition . 为了解决这个问题,我在函数定义中添加了extern "C" After this, the compiler generated a function name that is callable from C. 此后,编译器生成了可从C调用的函数名称。

Technically, the extern "C" only needs to be specified on the function declaration. 从技术上讲,仅在函数声明中指定extern "C"即可。 Is this right? 这是正确的吗? (The C++ FAQ has a good example of this.) Should you also specify it on the function definition? C ++ FAQ中有一个很好的例子。)是否还要在函数定义中指定它?

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. 无论如何,我都想咨询stackoverflow以确保我知道哪一种在技术上是“正确的”方法。

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. 只要定义具有声明并且在定义的编译中已经看到,在函数定义上就不需要' extern "C" '。 The standard specifically states (7.5/5 Linkage specifications): 该标准特别声明(7.5 / 5链接规范):

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. 但是,我通常也会在定义上加上' extern "C" ',因为它实际上是具有extern“ C”链接的函数。 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. 很多人讨厌不必要的冗余内容(例如将virtual放在方法重写上),但是我不是其中之一。

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: 使用命令nm查看已编译文件中的符号:


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. 显然,这表明声明为extern“ C”的函数的名称没有被篡改,并且定义时不需要extern“ C”关键字。
Had it required every C library code written without extern "C" would have been unusable in C++ programs. 如果它要求每个不带外部“ C”编写的C库代码在C ++程序中将无法使用。

The extern "C" around the definition is not required. 不需要在定义周围加上extern "C" 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 ". 您的代码正在寻找预处理器宏“ __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. 在您的示例中,您还在声明周围使用了extern "C" ,但是您没有在检查“ __cplusplus ”宏,这就是为什么我怀疑它一旦执行就可以工作的原因。

See the comments below — Standard C++ requires the __cplusplus macro to be defined by the preprocessor. 请参阅下面的注释-标准C ++要求__cplusplus宏由预处理器定义。

Just encountered this situation... Not a pleasant experience. 刚遇到这种情况。

The following was declared in one of my c files: 在我的一个c文件中声明了以下内容:

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

Next somewhere in a cpp file I defined: 接下来,在我定义的cpp文件中的某个位置:

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! 我花了一段时间才弄清楚我对AD转换所做的一切正确,但是我未能在定义中添加“ extern C”!

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 ... 我认为这里需要澄清,因为我有一个类似的问题,花了我一段时间才弄清楚了,只有布鲁克斯·摩西(Brooks Moses)正确地指出了这一点,我认为需要更清楚地说明。 。

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. 总而言之,标头可能会让您失望,编译器看到的只是cpp文件,如果标头不包含在extern“ C”中,则返回到您的cpp中(我通常会看到),那么extern“ C”将需要位于cpp文件中的某个位置(无论是在定义中还是在其他声明中),因此CXX编译器可以知道使用C链接进行编译,因此,编译器不关心标题,而仅关心链接器。

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). 编译器在编译调用站点(可能只能看到一个声明)时需要知道使用C符号名称和调用约定,并且编译器还需要在生成C站点时知道生成C符号名称并使用C调用约定。函数定义本身(可能看不到任何其他声明)。

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. 现在,如果您有一个在定义所在的翻译单元中可以看到的extern-C声明,则可以摆脱定义中的extern-C,但是我不确定。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM