46

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

extern void f();

// or only 

void f();
  1. 仅在使用时C
  2. 使用时从C++.
4

5 回答 5

55

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

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

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

于 2012-07-29T20:48:38.230 回答
25

在 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它包含在标题中。

于 2012-07-29T20:49:44.550 回答
5

对于一般用途,声明为

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

否则,extern就过时了。

于 2012-07-29T20:40:35.607 回答
1

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

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

extern 关键字对 C 函数的影响

于 2012-07-29T20:49:03.377 回答
1

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

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

于 2012-07-29T20:41:35.523 回答