【C语言】大程序结构
一、多个源代码文件
随着项目的内容逐渐增多,我们不可能把所有代码写在同一个文件中,将代码分散到多个文件中进行管理变得至关重要。
1.1 多个源文件代码
在实际的C语言项目中,很少会将所有代码都写在一个源文件。
多个源文件的使用可以将不同功能的代码进行模块划分,提高代码可读性、可维护性和复合型。
例如,我们可以创建一个 main.c 文件作为程序的入口,用于处理整体流程和调用其他功能模块;再创建 math.c 文件专门存放数学计算相关的函数。
e.p. 在 main.c 文件中:
#include <stdio.h>
#include "math.c"int main(){int a;scanf("%d", &a);int b;scanf("%d", &b);int result = add(a, b);printf("两数之和为%d", result);return 0;
}
在 math.c 中:
#include "math.h"int add(int num1, int num2){return num1 + num2;
}
⬇️
1.2 新建项目
像是如上的代码,需要新建一个文件夹,然后再创建 .c 文件:
在5.19文件夹下的 main.c 和 math.c 文件。
1.3 编译和构建
编写完成后,检验编译器是否报错,然后运行文件。
二、头文件
2.1 函数原型和头文件
- 函数原型:是的对函数的声明,它告知编译器函数的名称、参数类型和返回值类型,而不包含函数体的具体实现。
- 头文件:头文件的一个重要作用就是存放函数原型。当一个源文件中调用了另一个源文件中定义的函数时候,该源文件需要知道这个函数的原型,以便编译器在编译时进行语法查找和类型匹配。
例如,在前面的例子中,main.c 文件就调用了math.c 文件中的 add 函数,通过包含math.c 头文件,main.c 就获得了add 函数的原型,编译器就能正确处理函数调用。
2.2 include指令和头文件的引用
#include 指令用于将制定的头文件插入到当前源文件中。
C语言中有两种引用头文件的方式,一种是使用尖括号<>,如:
#include <stdio.h>
- 这种方式通常用于引用系统自带的标准头文件,编译器会在系统默认的头文件搜索路径中查找该头文件。
另一种是使用双引号"",如:
#include "math.c"
- 这种方式用于引用用户定义的头文件,编译器会先在当前源文件所在的目录中查找,若找不到再到系统默认路径查找 。
2.3 头文件的作用和使用方法
头文件除了声明函数原型外,还可以用于定义宏常量、结构体类型、枚举类型以及声明全局变量等。
例如,在一些图形绘制的项目中,可以在头文件中定义一些宏常量来表示颜色值,如:
#define RED 0x0000FF;
定义结构体类型来表示点的坐标,如:
typedef struct {int x; int y;}Point
在使用头文件时,首先要在源文件中使用 #include 指令包含相应的头文件,然后就可以使用头文件中定义的内容。
同时,为了防止头文件被重复包含,通常会使用条件编译指令,如 #ifndef 、#define 和 #endif ,如前面 math.h 头文件中的写法,这样可以避免因为重复包含导致的编译错误。
2.4 静态本地变量和局部函数
静态本地变量在函数调用结束后不会被销毁,其值会一直保留到程序结束,常用于在函数内部记录一些状态信息。
局部函数是值在一个函数内部定义的函数,它的作用域仅限于包含它的函数内部。
在头文件中一般不会声明局部函数,但对于静态本地变量,如果希望在多个源文件中共享其状态,可以在头文件中进行声明(是声明,不是定义),然后在一个源文件中进行定义。
三、声明
3.1 全局变量的声明和定义
全局变量是在函数外部定义的变量,其作用域从定义域开始到整个源文件结束,甚至可以通过extern关键字在其他源文件中使用。
全局变量的定义只会在一个源文件中进行,如:
int global_v = 10;
而在其他源文件中如果要使用该全局变量,就需要进行声明:
extern int global_v;
声明的目的是告诉编译器该变量在其他地方已经定义,让编译器在编译时能够正确处理对该变量的引用。
3.2 变量的定义和声明
变量的定义是为变量分配内存空间并进行初始化(也可以不初始化),而声明只是告诉编译器变量的存在及其类型,不分配内存空间,例如:
int num = 5; //这是定义,分配内存并初始化extern int other_n; //这是声明,告诉编译器变量存在
在一个源文件中,一个变量可以有多次声明,但只能有一次定义。
3.3 头文件的重复引用问题
如果在多个源文件中都包含同一个头文件,且头文件中没有使用条件编译防止重复包含,就会出现重复定义的错误。
例如,头文件中定义了一个全局变量,多个源文件包含该头文件后,就相当于在多个地方定义了同一个全局变量,这不符合C语言的语法规则。
通过上述2.3中的 #ifndef 、#define 和 #endif 条件编译指令,可以确保头文件的内容在一个源文件中只被包含一次,有效避免重复引用问题。
3.4 标准头文件结构
一个标准的C语言头文件通常包含以下几部分;首先是防止重复包含的条件编译指令,如#ifndef HEADER_NAME_H、#define HEADER_NAME_H和#endif ;然后是宏定义,用于定义一些常量或简单的代码片段;接着是结构体、枚举类型和定义;再之后是函数原型的声明;如果有需要再多个源文件中共享的全局变量,也会在这里进行声明(使用extern关键字)。
例如:
#ifndef MY_HEADER_H
#define MY_HEADER_H#define PI 3.1415926typedef struct {int width;int height;
} Rectangle;int calculate_area(Rectangle rect);extern int global_count;#endif
3.5 编译器对头文件的处理
当编译器遇到#include 指令时,会暂停当前源文件的编译,将头文件的内容插入到 #include 指令所在的位置,然后继续编译。
- 对于系统标准头文件,编译器会在其默认的搜索路径中查找;对于用户自定义头文件,先在当前源文件目录查找,找不到再到系统默认路径查找。
- 如果头文件中包含其他头文件的引用,编译器会按照同样的方法递归处理,直到所有头文件内容都被正确插入并编译完成。
🌟个人主页🌟
这个姑且算作是草稿,正式的我会另外新开一个合集,我感觉这个中间的逻辑没写好,新的我会重新写个大纲来整理,这个合集基本是按照翁恺老师的大纲写的。
正式的我也会发在GitHub上