繁体   English   中英

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

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

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

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

从技术上讲,仅在函数声明中指定extern "C"即可。 这是正确的吗? C ++ FAQ中有一个很好的例子。)是否还要在函数定义中指定它?

这是一个示例来证明这一点:

/* ---------- */
/* "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”关键字。
如果它要求每个不带外部“ C”编写的C库代码在C ++程序中将无法使用。

不需要在定义周围加上extern "C" 您可以将其放在声明周围。 您的示例中有一个音符...

#ifdef __cplusplus
extern "C" {
#endif

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

#ifdef __cplusplus
}
#endif

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

虽然通常实现,但可能会或可能不会定义,具体取决于您的编译器。 在您的示例中,您还在声明周围使用了extern "C" ,但是您没有在检查“ __cplusplus ”宏,这就是为什么我怀疑它一旦执行就可以工作的原因。

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

刚遇到这种情况。

在我的一个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链接进行编译,因此,编译器不关心标题,而仅关心链接器。

它应该同时存在。 编译器在编译调用站点(可能只能看到一个声明)时需要知道使用C符号名称和调用约定,并且编译器还需要在生成C站点时知道生成C符号名称并使用C调用约定。函数定义本身(可能看不到任何其他声明)。

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

暂无
暂无

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

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