在C语言中,编译源文件是从第一行到最后一行,逐行编译的,而且在多个文件同时编译时,是逐个文件编译的,即无全局预扫描,所以严格要求调用前需要出现定义或声明。因此变量和函数的调用是在定义/声明之后的,本文将主要介绍变量和函数如何在C中定义和声明。
一、概念详解
1、定义变量(definition):分配内存,只能出现一次;写在任意一个.c源文件全局区
2、声明外部全局变量(declaration):告诉编译器这个变量名存在、类型存在、内存在别文件,不分配内存;使用关键字extern,可写在其他.c或.h文件。
3、变量的定义和声明
外部变量(非本文件中定义的变量):extern 变量的类型 变量名
本部变量: 变量类型 变量名
4、函数的定义和声明
外部函数(非本文件中定义的函数):extern 外部函数头
本部函数:函数头
函数的声明:形参的名字可以不要,也可以要,但是类型一定要
c
extern def_v(int,int);
extern def_v(int a,int b);
二、工程示例
1、定义变量和函数的源文件
c
#include<stdio.h>
#include<windows.h>
//全局变量定义,分配内存和初始化
int global_num=666;
char global_str[]="跨文件变量";
void print_def(void){
SetConsoleOutputCP(65001);
SetConsoleCP(65001);
printf("测试全局变量访问和函数调用%d %s\n",global_num,global_str);
}
2、调用外部变量和函数的源文件
c
extern int global_num;
extern char global_str[];
extern void print_def(void);
int main(int argc, char const *argv[])
{
/* code */
SetConsoleOutputCP(65001);
SetConsoleCP(65001);
printf("主函数在调用外部全局变量%d %s\n",global_num,global_str);
global_num = 888;
print_def();
return 0;
}
3、编译与运行结果
由于存在多个源文件,所以编译多个.c文件均需要编译(把所有.c源文件一次性交给gcc,gcc自动处理跨文件extern关联)

补充:
C语言编译分为编译阶段和链接阶段
编译阶段:单个.c生成目标文件.o,只做语法检查,extern只做标记,不寻找变量实体;
链接阶段:把所有.o文件合并,解析extern对应的真是变量的内存地址,找不到则报"undefined reference"链接错误
4、推荐global.h头文件统一存放extern声明
在实际项目中,每个c文件重复写extern,全局变量管理比较混乱,建议统一放到头文件。
之后任意.c文件只需要#include global.h,就会自动导入所有外部变量和函数声明,不用重复写extern。
三、常见错误与原因
当所有.c文件里都没有写变量定义,但是写了extern int 变量名,链接器就找不到变量实体,会报错
