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

我写了一个C ++函数,我需要从C程序调用。 为了使它可以从C调用,我在函数声明中指定了extern "C" 。 然后我编译了C ++代码,但编译器(Dignus Systems / C ++)为该函数生成了一个错位的名称 。 所以,它显然没有尊重extern "C"

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

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

这是一个certificate这一点的例子:

 /* ---------- */ /* "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以确保我知道哪种技术上是“正确的”方式。

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

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

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

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

 // 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 ++程序中使用。

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

在我的一个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) { ... } 

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

我认为这需要在这里澄清,因为我遇到了类似的问题,我花了一些时间才清楚地知道这一点,只有Brooks Moses正确地触及了这一点,我认为需要更明确地说明这一点。 。

总而言之,标题可能会让你失望,所有编译器看到的都是cpp文件,如果标题没有包含在extern“C”中回到你的cpp(我常见),那么extern“C”将需要在某个地方的cpp文件中(无论是在定义中,还是在另一个声明中),因此CXX编译器可以知道使用C链接,编译器不关心头,只关注链接器。

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

 #ifdef __cplusplus extern "C" { #endif /* Function declaration */ void foo(int); #ifdef __cplusplus } #endif 

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

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

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

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

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