【发布时间】:2012-07-29 20:34:45
【问题描述】:
在C 库的*.h 头文件中,是否应该声明函数
extern void f();
// or only
void f();
- 仅在
C中使用时 - 从
C++使用时。
【问题讨论】:
在C 库的*.h 头文件中,是否应该声明函数
extern void f();
// or only
void f();
C 中使用时
C++使用时。【问题讨论】:
在 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++时这是一个常见的解决方案。
extern "C",而不是extern。
在 C 库的头文件中,是否应该声明函数:
extern void f(); // or only void f();
在 C++ 程序中,函数被声明为不返回值且不带参数的函数。
在 C 程序中,函数被声明为不返回值并采用不确定但不是可变长度的参数列表的函数。
要在 C 中获得“无参数”的含义,请使用以下之一:
extern void f(void);
void f(void);
同样的符号在 C++ 中也意味着同样的事情,尽管对于纯 C++ 代码,在参数列表中使用 void 并不习惯(不要在纯 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++ 都可以使用标头。
宏通常会在一个通用头文件中定义,该头文件在任何地方都可以使用,然后特定头文件会确保包含通用头文件,然后使用适当形式的宏。
正式地,在函数声明之前不需要extern 符号。但是,我在标头中使用它是为了强调它是对外部定义函数的声明,并且与标头中声明全局变量的那些(罕见)场合对称。
人们可以并且确实对此存在分歧;我遵循当地规则——但当我是规则制定者时,extern 包含在标题中。
【讨论】:
一般用途声明为
#ifdef __cplusplus
extern "C" {
#endif
void f(void);
#ifdef __cplusplus
}
#endif
否则,extern 已过时。
【讨论】:
extern template。
后者非常好,因为它只是一个函数定义,它告诉那些包含此标头的人:'这里有一个带有此原型的函数'
在这种情况下,函数明显不同于变量,但这是另一回事。 但请确保您不包含函数体,除非您将其声明为“内联”或作为类定义 (C++) 的一部分或作为“模板函数”(也是 C++)。
【讨论】:
在函数原型中指定 extern 无效,因为它是默认假定的。每当编译器看到一个原型时,它假定一个函数是在其他地方定义的(在当前或另一个翻译单元中)。这适用于两种语言。
以下线程有一些关于 extern 的一般有用的 cmets。
【讨论】: