预处理
1.C语言在对源程序进行编译之前,会先对一些特殊的预处理指令作解释(比如之前使用的#include文件包含指令),产生一个新的源程序(这个过程称为编译预处理),之后再进行通常的编译
2.为了区分预处理指令和一般的C语句,所有预处理指令都以符号"#"开头,并且结尾不用分号
3.预处理指令可以出现在程序的任何位置,它的作用范围是从它出现的位置到文件尾。习惯上我们尽可能将预处理指令写在源程序开头,这种情况下,它的作用范围就是整个源程序文件
4.C语言提供的预处理指令主要有:宏定义、 条件编译、 文 件包含
2.为了区分预处理指令和一般的C语句,所有预处理指令都以符号"#"开头,并且结尾不用分号
3.预处理指令可以出现在程序的任何位置,它的作用范围是从它出现的位置到文件尾。习惯上我们尽可能将预处理指令写在源程序开头,这种情况下,它的作用范围就是整个源程序文件
4.C语言提供的预处理指令主要有:宏定义、 条件编译、 文 件包含
4.预处理指令在代码翻译成0和1之前执行
5.预处理的位置是随便写的
6.预处理指令的作用域:从编写指令的那一行开始,一直到文件结尾,可以用#undef取消宏定义的作用
5.预处理的位置是随便写的
6.预处理指令的作用域:从编写指令的那一行开始,一直到文件结尾,可以用#undef取消宏定义的作用
7.宏名一般用大写或者以k开头,变量名一般用小写
不带参数的宏定义
1.一般形式
#define 宏名 字符串
比如#define ABC 10
右边的字符串也可以省略,比如#define ABC
1.一般形式
#define 宏名 字符串
比如#define ABC 10
右边的字符串也可以省略,比如#define ABC
2.作用
它的作用是在编译预处理时,将源程序中所有"宏名"替换成右边的"字符串",常用来定义常量。
它的作用是在编译预处理时,将源程序中所有"宏名"替换成右边的"字符串",常用来定义常量。
3.使用习惯与注意
1> 宏名一般用大写字母,以便与变量名区别开来,但用小写也没有语法错误
2> 对程序中用双引号扩起来的字符串内的字符,不进行宏的替换操作。
3> 在编译预处理用字符串替换宏名时,不作语法检查,只是简单的字符串替换。只有在编译的时候才对已经展开宏名的源程序进行语法检查
2> 对程序中用双引号扩起来的字符串内的字符,不进行宏的替换操作。
4> 宏名的有效范围是从定义位置到文件结束。如果需要终止宏定义的作用域,可以用#undef命令
5> 定义一个宏时可以引用已经定义的宏名
#include <stdio.h>
//#define kCount 4
int main()
{
char *name = "COUNT";
printf("%s\n", name);
#define COUNT 4
int ages[COUNT] = {1, 2, 67, 89};
for ( int i = 0; i<COUNT; i++) {
printf("%d\n", ages[i]);
}
// 从这行开始,COUNT这个宏就失效
#undef COUNT
int a = COUNT;
return 0;
}
带参数的宏定义
1.一般形式
#define 宏名(参数列表) 字符串
2.作用
在编译预处理时,将源程序中所有宏名替换成字符串,并且将 字符串中的参数 用 宏名右边参数列表 中的参数替换
1.一般形式
#define 宏名(参数列表) 字符串
2.作用
在编译预处理时,将源程序中所有宏名替换成字符串,并且将 字符串中的参数 用 宏名右边参数列表 中的参数替换
3.使用注意
1> 宏名和参数列表之间不能有空格,否则空格后面的所有字符串都作为替换的字符串
1> 宏名和参数列表之间不能有空格,否则空格后面的所有字符串都作为替换的字符串
2> 带参数的宏在展开时,只作简单的字符和参数的替换,不进行任何计算操作。所以在定义宏时,一般用一个小括号括住字符串的参数。
int sum(int a, int b)
{
return a + b;
}*/
#include <stdio.h>
#define sum(v1, v2) ((v1)+(v2))
#define pingfang(a) ((a)*(a))
int main()
{
// pingfang(5+5) (10*10)
// pingfang(5+5)
// pingfang(5+5) (35)
// pingfang(5+5)/pingfang(2)
int c = pingfang(5+5)/pingfang(2);
printf("c is %d\n", c);
/*
int c = sum(2, 3) * sum(6, 4);
printf("c is %d\n", c);*/
/*
int a = 10;
int b = 20;
int c = sum(a, b);
printf("c is %d\n", c);
//int c = sum(a, b);*/
return 0;
}
与函数的区别
从整个使用过程可以发现,带参数的宏定义,在源程序中出现的形式与函数很像。但是两者是有本质区别的:
1> 宏定义不涉及存储空间的分配、参数类型匹配、参数传递、返回值问题
2> 函数调用在程序运行时执行,而宏替换只在编译预处理阶段进行。所以带参数的宏比函数具有更高的执行效率
1> 宏定义不涉及存储空间的分配、参数类型匹配、参数传递、返回值问题
2> 函数调用在程序运行时执行,而宏替换只在编译预处理阶段进行。所以带参数的宏比函数具有更高的执行效率
条件编译
在很多情况下,我们希望程序的其中一部分代码只有在满足一定条件时才进行编译,否则不参与编译(只有参与编译的代码最终才能被执行),这就是条件编译。
基本用法
1 #if 条件1
2 ...code1...
3 #elif 条件2
4 ...code2...
5 #else
6 ...code3...
7 #endif
2> 如果条件1不成立、条件2成立,那么编译器就会把#elif 与 #else之间的code2代码编译进去
3> 如果条件1、2都不成立,那么编译器就会把#else 与 #endif之间的code3编译进去
4> 注意,条件编译结束后,要在最后面加一个#endif,不然后果很严重(自己思考一下后果)
5> #if 和 #elif后面的条件一般是判断宏定义而不是判断变量,因为条件编译是在编译之前做的判断,宏定义也是编译之前定义的,而变量是在运行时才产生的、才有使用的意义