[英]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.