预处理命令
预处理命令不属于C语言本身组成部分
编译过程:预处理->编译->汇编->链接
预处理阶段只做文本的原样替换
预处理包含:
- 宏定义
- 条件包含
- 条件编译
宏定义
定义符号常量,预处理时将宏名用宏值原样替换(除""
中内容)
语法:#define 宏名 宏值
(例如#define N 100
表示定义一个宏N
,其代表值为100
)
预处理阶段只做文本的原样替换,这意味着宏定义不需要;
结尾,否则会将分号也替换上来
宏定义只能放在一行,如果需要多行则需要使用续行符\
,该行续航符后面不能有任何内容
#define REPLACE 89+59\
+96
用途:当作常量来用,可以做到一改全改,方便操作
宏名命名原则:符合标识符命名规则,不要和关键字重名,为和普通变量区分一般建议全大写
带参数的宏定义:
#define MUL(a,b) a*b
....
area = MUL(half1,half2);
注意带参数的宏不是函数,由于宏是文本的原样替换,故宏替换过程中会有副作用,例如上例假如area=MUL(1+1,2+2)
,实际式子为1+1*2+2
值为5而非8,与预期不符.
故宏编写过程中,能加括号的尽量都加括号,例如上面定义宏可以改为#define MUL(a,b) ((a)*(b))
- 带参宏:在预处理阶段发挥作用,做的只是文本替换,并不做类型检查,参数没有类型
- 函数:运行阶段发挥作用,形参,都有明确类型
宏的作用域:仅define,则该宏从被define开始到本文件最后都有效
如需要限定宏在一定作用域,可使用#undef 宏名
取消宏,则作用域会限制在#define
所在行到#undef
所在行之间
条件包含
#include "文件名"
首先在当前路径下寻找要包含的文件,找不到再到系统指定路径下寻找#include <文件名>
默认到系统指定路径(一般为/usr/include)下寻找头文件
作用:将文件名代表的文件中内容替换到当前文件
文件名可包含路径,例如#include "dir1/file1.c"
来调用不在当前目录下的文件
条件编译
本质亦是文本替换,替换符合条件的文本
语法:
//形式1,判断是否 定义 标识符
#ifdef 标识符
程序段1 //如果定义了标识符N,编译程序段1
#else //else部分可选
程序段2 //(有#else情况下)否则编译程序段2
#endif
//形式2,判断是否 未定义 标识符
#ifndef 标识符
程序段1 //如果未定义标识符N,编译程序段1
#else //else部分可选
程序段2 //(有#else情况下)否则编译程序段2
#endif
//形式3,判断表达式是否为真
#if 表达式
程序段1 //表达式为真(非0)时编译程序段1
#else //else部分可选
程序段2 //(有#else情况下)否则编译程序段2
#endif
条件编译常见用于头文件,防止重复定义
#ifndef _ADD_H_ //这段条件编译起到防止重复定义的作用
#define _ADD_H_
struct stu
{
int sno;
char name[20];
};
extern int add(int a,int b);
#endif
多文件编程
- 有一个主程序
main.c
- 其他文件,每个
文件名.c
都应该有一个对应的文件名.h
头文件,main.c
引用需要的文件名.h
来运用其中函数 - 头文件内一部分是对外的函数声明,一部分是自己的
.c
需要的头文件,变量结构声明宏等内容 - gcc编译时应该将所有用到的文件编译