函数声明只需要extern“C”吗?

时间:2009-09-04 18:30:02

标签: c++ c extern extern-c

我编写了一个C ++函数,我需要从C程序调用它。为了使其可以从C调用,我在函数声明上指定了extern "C"。然后我编译了C ++代码,但编译器(Dignus Systems / C ++)为该函数生成了mangled name。所以,它显然不尊重extern "C"

要解决此问题,我在功能定义中添加了extern "C"。在此之后,编译器生成了一个可从C调用的函数名称。

从技术上讲,只需要在函数声明中指定extern "C"。这是正确的吗? (C++ FAQ Lite就是一个很好的例子。)你是否也应该在函数定义中指定它?

这是一个证明这一点的例子:

/* ---------- */
/* "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...
}

我的问题可能是错误编码的结果,或者我可能发现了编译器错误。在任何情况下,我都想咨询stackoverflow以确保我知道哪种技术上是“正确”的方式。

6 个答案:

答案 0 :(得分:33)

只要声明具有并且已经在定义的编译中看到,就不应该在函数定义上要求'extern "C"'。该标准明确规定(7.5 / 5链接规范):

  

在看到明确的链接规范之后,可以在没有链接规范的情况下声明函数;前面声明中明确指定的链接不受此类函数声明的影响。

但是,我通常也将'extern "C"'放在定义上,因为它实际上是一个带有extern“C”链接的函数。很多人讨厌不必要的,冗余的东西在声明上(比如把virtual放在方法覆盖上),但我不是其中之一。

答案 1 :(得分:2)

修改:
好像我误解了这个问题。 无论如何,我试过了:


// 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);

使用命令nm查看编译文件中的符号:


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

这清楚地表明声明为extern“C”的函数的名称没有被破坏,并且在定义时不需要extern“C”关键字。
如果它需要在没有extern“C”的情况下编写的每个C库代码都无法在C ++程序中使用。

答案 2 :(得分:1)

定义周围的extern "C"不是必需的。你可以把它放在声明周围。你的例子中有一个注释......

#ifdef __cplusplus
extern "C" {
#endif

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

#ifdef __cplusplus
}
#endif

您的代码正在寻找预处理器宏“__cplusplus”。

虽然它通常是实现的,但根据您的编译器,这可能会也可能不会被定义。在您的示例中,您还在声明周围使用extern "C",但是您检查“__cplusplus”宏,这就是为什么我怀疑它一旦你做到了。

请参阅下面的注释 - 标准C ++要求预处理器定义__cplusplus宏。

答案 3 :(得分:1)

刚遇到这种情况......不是一次愉快的经历。

以下是我的一个c文件中声明的内容:

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

在我定义的cpp文件中的某个地方:

void ADC_IRQHandler(void) {                                                                                  
    ...
}

我忘了将前方声明改为:

void ADC_IRQHandler(void);

我花了一段时间才发现我在AD转换方面做的一切正确,但我没有在定义中添加“extern C”!

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

我的两分钱为什么在某些情况下习惯将其添加到定义中可能会有用。

答案 4 :(得分:1)

我认为这需要在这里澄清一下,因为我遇到了类似的问题,我花了一些时间才明白这一点,只有布鲁克斯摩西才能正确地触及这一点,我认为需要更多说明显然......

总之,标题可能会让你失望,编译器看到的所有内容都是cpp文件,如果标题不包含在extern中,那么C&#34;回到你的cpp(我常见),然后是extern&#34; C&#34;将需要在某个地方的cpp文件中(在定义或其他声明中),以便CXX编译器可以知道使用C链接,编译器不关心标头,只关心链接器。

答案 5 :(得分:0)

应该是两者兼而有之。编译调试调用站点时,编译器需要知道使用C符号名称和调用约定(可能只看到声明),编译器还需要知道生成C符号名称并在编译时使用C调用约定。函数定义本身(可能看不到任何其他声明)。

现在,如果你有一个从定义存在的翻译单元可见的extern-C声明,你可以从定义中删除extern-C,但我不知道那肯定是。

相关问题