C 与 C++ 中的外部函数

Posted

技术标签:

【中文标题】C 与 C++ 中的外部函数【英文标题】:Extern functions in C vs C++ 【发布时间】:2012-07-29 20:34:45 【问题描述】:

C 库的*.h 头文件中,是否应该声明函数

extern void f();

// or only 

void f();
    仅在C 中使用时 从C++使用时。

【问题讨论】:

【参考方案1】:

在 C 或 C++ 中声明函数时,[几乎] 永远不需要使用关键字 extern。在 C 和 C++ 中,所有函数默认都有外部链接。在头文件中用extern 声明函数的奇怪习惯可能有一些历史根源,但几十年来它已经完全无关紧要了。

上面的 C 语言中有一个 [obscure?] 异常,这可能与您要问的问题没有直接关系:在 C 语言 (C99) 中,如果在某些翻译单元中,函数被定义为 inline 并且声明为extern(使用显式extern),则该函数的内联定义也用作外部定义。如果翻译单元中不存在显式 extern 的声明,则内联定义仅用作“内部”定义。

附: C++中有extern "C"这样的东西,但那是完全不同的事情。

【讨论】:

今天extern关键字经常用于通过JNI将C/C++代码绑定到Java,例如在android上使用C/C++时这是一个常见的解决方案。 @user827992:我很确定您在声明函数时说的是extern "C",而不是extern【参考方案2】:

在 C 库的头文件中,是否应该声明函数:

extern void f();
// or only
void f();

问题 1:语义

在 C++ 程序中,函数被声明为不返回值且不带参数的函数。

在 C 程序中,函数被声明为不返回值并采用不确定但不是可变长度的参数列表的函数。

要在 C 中获得“无参数”的含义,请使用以下之一:

extern void f(void);
void f(void);

同样的符号在 C++ 中也意味着同样的事情,尽管对于纯 C++ 代码,在参数列表中使用 void 并不习惯(不要在纯 C++ 代码中这样做)。

问题 2:C 和 C++ 之间的交互

很棘手,但通常的规则是您应该将 C++ 代码中的函数声明为 extern "C"。要为两者使用相同的源代码,您需要测试__cplusplus 宏。你通常会这样做:

#ifdef __cplusplus
#define EXTERN_C       extern "C"
#define EXTERN_C_BEGIN extern "C" 
#define EXTERN_C_END   
#else
#define EXTERN_C       /* Nothing */
#define EXTERN_C_BEGIN /* Nothing */
#define EXTERN_C_END   /* Nothing */
#endif

EXTERN_C void f(void);

EXTERN_C_BEGIN
    void f(void);
    int  g(int);
EXTERN_C_END

选项和变体多种多样,但 C 和 C++ 都可以使用标头。

宏通常会在一个通用头文件中定义,该头文件在任何地方都可以使用,然后特定头文件会确保包含通用头文件,然后使用适当形式的宏。

问题 3:风格

正式地,在函数声明之前不需要extern 符号。但是,我在标头中使用它是为了强调它是对外部定义函数的声明,并且与标头中声明全局变量的那些(罕见)场合对称。

人们可以并且确实对此存在分歧;我遵循当地规则——但当我是规则制定者时,extern 包含在标题中。

【讨论】:

他们错过了';'是我的错我已经解决了这个问题。 感谢@LokiAstari 的精心编辑。我看到问题是如何变成原来的样子的,您对我的回答的编辑是有道理的。 (我在最后一句话中犯了一个轻微的错误,这就是为什么它现在最后一次由我编辑。) @JonathanLeffler +1 第 3 期,我认为您不必拥有 extern(C++ 中的 extern "C" 除外)。 (更新)我更喜欢在标题中省略 extern 并使用规则:如果它是静态的,它是 not 公开的,如果它不是静态的,它是公开的。我要对 OP 说,应该声明函数 void foo(void);但最好遵守当地的规定。另外,我同意只在 .c 文件中定义静态函数,而不是在 .h 文件中。【参考方案3】:

一般用途声明为

#ifdef __cplusplus
extern "C" 
#endif
  void f(void);
#ifdef __cplusplus

#endif

否则,extern 已过时。

【讨论】:

也许你应该添加那个漂亮的定义'#ifdef _CPLUSPLUS'(或者你的编译器用来区分CPP和C模式的任何东西)。 现在 C++11 为 extern 关键字添加了新的语义含义,例如 extern template【参考方案4】:

后者非常好,因为它只是一个函数定义,它告诉那些包含此标头的人:'这里有一个带有此原型的函数'

在这种情况下,函数明显不同于变量,但这是另一回事。 但请确保您不包含函数体,除非您将其声明为“内联”或作为类定义 (C++) 的一部分或作为“模板函数”(也是 C++)。

【讨论】:

【参考方案5】:

在函数原型中指定 extern 无效,因为它是默认假定的。每当编译器看到一个原型时,它假定一个函数是在其他地方定义的(在当前或另一个翻译单元中)。这适用于两种语言。

以下线程有一些关于 extern 的一般有用的 cmets。

Effects of the extern keyword on C functions

【讨论】:

以上是关于C 与 C++ 中的外部函数的主要内容,如果未能解决你的问题,请参考以下文章

C++ 成员函数作为外部库的回调函数

c++中的external function啥意思

外部“C”是不是应包含 C++ 函数的声明或定义?

外部链接的 C 库中的异常传播

python如何调用C++外部库中的类?

如何使用 MSVC 在 C++ 中定义外部 C 结构返回函数?