一.预处理指令
1.C语言在对源程序进行编译之前,会先对一些特殊的预处理指令作解释(比如之前使用的#include文件包含指令),产生一个新的源程序(这个过程称为编译预
处理),之后再进行通常的编译(预处理指令在代码翻译成0和1之前执行)
2.为了区分预处理指令和一般的C语句,所有预处理指令都以符号"#"开头,并且结尾不用分号
3.预处理指令可以出现在程序的任何位置,它的作用范围是从它出现的位置到文件尾。习惯上我们尽可能将预处理指令写在源程序开头,这种情况下,它的作
用范围就是整个源程序文件
4.C语言提供的预处理指令主要有:宏定义、文件包含、条件编译
二.宏定义
1.不带参数的宏定义
(1)一般形式: #define 宏名 字符串(比如:#define ABC 10),右边的字符串也可以省略,比如:#define ABC
(2)作用:它的作用是在编译预处理时,将源程序中所有“宏名”替换成右边的“字符串”,常用来定义常量。
(3)使用习惯与注意:
<1>宏名用大写字母
<2>对程序中用双引号括起来的字符内的字符,是不进行宏的替换操作。
<3>在编译预处理用字符串替换宏名时,不作语法检查,只是简单的字符串替换。只有在编译的时候,才对已经替换宏名的源程序进行语法检查。
<4>宏名的有效范围是从定义位置到文件结束,如果需要终止宏定义的作用域,可以用#undef命令(作用域截止)。
<5>定义一个宏时可以引用已经定义的宏名
2.带参数的宏定义
(1)一般形式:#define 宏名(形参数列表) 字符串
(2)作用:在编译预处理时,将源程序中所有宏名宏名(实参数列表)成字符串,并且将字符串中的形参数用宏名右边实参数列表中的参数替换。
#include
#define average(a, b) ((a)+(b)/2)
int main ()
{
int a = average(10, 4); // 会被替换成:int a = (10+4)/2
printf("平均值:%d", a);
return 0;
}
(3)使用注意:
<1>宏名和参数列表之间不能有空格,否则空格后面的所有的所有字符串都作为替换的字符串。
<2>带参数的宏在展开时,只作简单的字符和参数的替换,不进行任何计算操作。所以在定义宏时,用一个小括号括住字符串的参数,并且计算结果也用括号括起来:a+b要写成((a)+(b))
(4)与函数的区别
从整个使用过程可以发现,带参数的宏定义,在源程序中出现的形式与函数很像。但是两者是有本质区别的:
<1> 宏定义不涉及存储空间的分配、参数类型匹配、参数传递、返回值问题
<2> 函数调用在程序运行时执行,而宏替换只在编译预处理阶段进行。所以带参数的宏比函数具有更高的执行效率
二.条件编译
在很多情况下,我们希望程序的其中一部分代码只有在满足一定条件时才进行编译,否则不参与编译(只有参与编译的代码最终才能被执行),这就是条件编译。
1.基本用法
#if 条件1
代码1
#elif 条件2
代码2
#else
代码3
#endif
(1)如果条件1成立,那么编译器就会把#if 与 #elif之间的代码1代码编译进去(注意:是编译进去,不是执行,和平时用的if-else是不一样的)
(2)如果条件1不成立、条件2成立,那么编译器就会把#elif 与 #else之间的代码2代码编译进去。
(3)如果条件1、2都不成立,那么编译器就会把#else 与 #endif之间的代码3编译进去。
(4)注意,条件编译结束后,一定要在最后面加一个#endif,不然后果很严重(endif是不参加编译的结束标准,不写的话,后面全部都会消失,不会参加编译)。
(5)#if 和 #elif后面的条件一般是判断宏定义而不是判断变量,因为条件编译是在编译之前做的判断,宏定义也是编译之前定义的,而变量是在运行时才产生的、才有使用的意义。
(6)例子:
#define MAX 25
int main()
{
#if MAX == 0
printf("MAX是0");
#elif MAX > 0
printf("MAX大于0");
#else
printf("MAX大于0");
#endif
return 0;
}
2.其它用法
(1)#if define() 和if !defined()的用法
<1>#if和#elif后面的条件不仅仅可以用来判断宏的值,还可以判断是否定义过某个宏
#if defined(宏) // 判断这个宏定义过没有,定义过则执行代码
代码
#endif
<2>if !defined(宏)是判断这个宏如果没有定义,则执行代码。
(2)#ifdef和ifndef的使用
<1>#ifdef的使用和if defined()的用法一致,只是一个不写括号,一个要写括号
<2>#ifndef的使用和if !defined()的用法一致,只是一个不写括号,一个要写括号
三.文件包含
1.其实我们早就有接触文件包含这个指令了, 就是#include,它可以将一个文件的全部内容拷贝另一个文件中。
2.一般形式:
<1>第一种形式:#include (直接到C语言库函数头文件所在的目录中查找文件)
<2>第二种:#include "文件名"(系统会先在源程序当前目录下寻找,若找不到,再到操作系统的path路径中查找,最后才到C语言库函数头文件所在目录中查找)
3.使用注意
(1)#include指令允许嵌套包含,比如a.h包含b.h,b.h包含c.h,但是不允许递归包含,比如 a.h 包含 b.h,b.h 包含 a.h。
(2)使用#include指令可能导致多次包含同一个头文件,降低编译效率。解决办法:
把函数声明写在这段代码中间:
#ifndef _文件名_H_
#define _文件名_H_
函数声明代码
#endif