你需要区分两个独立的概念:函数定义和符号声明。"extern"是一个链接修饰符,它向编译器提供一个关于后续引用的符号在哪里定义的提示(提示是“不在这里”)。
如果我写下:
extern int i;
在C文件中的文件范围(在函数块之外),你是在说“这个变量可能在其他地方定义”。
extern int f() {return 0;}
既是函数 f 的声明,也是函数 f 的定义。在这种情况下,定义会覆盖 extern。
extern int f();
int f() {return 0;}
首先是一个声明,接着是定义。
如果你想同时声明和定义一个文件作用域的变量,使用extern是错误的。例如,
extern int i = 4;
根据编译器的不同,会出现错误或警告。
如果你明确不想定义一个变量,使用extern
是很有用的。
让我解释一下:
假设文件a.c包含以下内容:
#include "a.h"
int i = 2;
int f() { i++; return i;}
文件 a.h 包含以下内容:
extern int i;
int f(void);
文件 b.c 包含以下内容:
#include <stdio.h>
#include "a.h"
int main(void){
printf("%d\n", f());
return 0;
}
在头文件中使用
extern
是有用的,因为它在链接阶段告诉编译器,“这是一个声明,而不是定义”。如果我删除a.c中定义
i
、为其分配空间并赋值的那一行,程序应该在编译时出现未定义的引用错误。这告诉开发者他引用了一个变量,但尚未定义它。另一方面,如果我省略了"extern"关键字,并删除
int i = 2
这一行,程序仍然可以编译 -
i
将被定义为默认值0。
文件作用域变量如果您没有显式赋值,将隐式定义为默认值0或NULL - 这与您在函数顶部声明的块作用域变量不同。extern关键字避免了这种隐式定义,从而帮助避免错误。
对于函数来说,在函数声明中,这个关键字确实是多余的。函数声明没有隐式定义。