C extern在函数声明中的作用
1-1 extern关键字
这个关键字是用于外部的声明和引用的,主要是用于声明一个文件定义的全局变量可以在外部的文件中被引用,对于函数声明中这个关键字的作用实际上是默认存在的,写或者是不写编译器默认是存在extern这个关键字的,这种编写函数声明的方式在大型的代码项目中得到广泛的应用。
首先,我应该回顾一下C语言的基础知识。在C语言中,函数的声明默认是extern的,也就是说,即使不写extern,函数声明也默认具有外部链接属性。所以,在函数声明前显式地加上extern可能并不是必须的,但有时候程序员为了代码的可读性,可能会明确写出extern,以强调这个函数是在其他源文件中定义的。
根据C标准,函数的声明默认就是extern,所以显式添加可能只是编码风格的问题,或者为了强调。而变量的情况不同,全局变量如果要在多个文件中使用,必须使用extern来声明,否则会导致重复定义。所以,对于函数来说,extern是可选的,但通常不写,而对于变量则必须写。
1-2 详细说明
对于函数声明而言,extern
是默认隐含的(即使不写,编译器也会自动视为外部链接)
extern void F_Dsp_Seg(U8* buf); // 显式声明
void F_Dsp_Signal(U8 state); // 隐式声明(与上一行等价)
两种写法完全等价,加不加 extern
均可。实际编码中,函数声明通常省略 extern【建议加上去】
。
1-3 extern编写原因
代码可读性:明确强调"此函数由外部模块实现",尤其在大型项目中,帮助开发者快速理解函数来源。
与变量声明风格统一:某些团队规范要求所有外部符号显式标注 extern
,保持代码一致性。
历史习惯:早期 C 标准对默认行为的规范不如现在清晰,老代码可能保留这一习惯。
1-4 extern真实的价值
与函数不同,全局变量的声明必须严格区分 extern
(声明)和非 extern
(定义):
// File1.c
int global_var = 42; // ✅ 定义(分配内存)
// File2.c
extern int global_var; // ✅ 声明(不分配内存,仅引用)
如果省略 extern
会导致重复定义:
// File2.c
int global_var; // ❌ 错误!与 File1.c 中的定义冲突
1-5 使用优点
-
模块化开发
允许将函数/变量定义集中在某一源文件(.c
),通过头文件(.h
)中的extern
声明共享给其他模块。 -
避免重复定义
确保头文件中的声明不会意外创建新的变量实例(对变量尤为重要)。 -
跨文件可见性控制
配合 static
关键字,可以精细控制符号的暴露范围:
static
函数/变量:仅在当前文件可见(内部链接)extern
函数/变量:全局可见(外部链接)
1-6 使用建议
函数声明:可省略 extern
,除非团队规范明确要求。
变量声明:在头文件中必须用 extern
声明全局变量,并在某一源文件中给出定义。
头文件保护:始终配合 #ifndef
或 #pragma once
防止多次包含。
1-7 使用场景
├── display.h // 声明函数
├── display.c // 实现函数
└── main.c // 使用函数
display.h
内容:
#pragma once
// 函数声明(extern 可省略但显式写出)
extern void F_Dsp_Seg(U8* buf);
extern void F_Dsp_Signal(U8 state);
display.c
内容:
#include "display.h"
// 函数实际实现
void F_Dsp_Seg(U8* buf) { /* ... */ }
void F_Dsp_Signal(U8 state) { /* ... */ }
main.c内容 :
#include "display.h" // 通过 extern 声明获得函数信息
int main() {
U8 buffer[10];
F_Dsp_Seg(buffer); // 正确链接到 display.c 中的实现
return 0;
}
通过这种组织方式,编译器在编译 main.c
时知道 F_Dsp_Seg
的存在,而链接器最终将 main.c
中的调用与 display.c
中的实现关联起来。