编译预处理是对C语言源程序编译前进行的预加工,这些操作是通过命令来实现的,即预编译命令,主要有三种,即宏定义、文件包含和条件编译。这些规定是由编译系统规定的,由于不是C语言本身的组成部分,因此不能直接编译,而要经过编译器预处理再与源程序进行编译
书写规则:#+关键字(一行书写一个)
宏定义
用一个指定的标识符(名字)来代表一个字符串
不带参数的宏定义
格式:#define 标识符 字符串
用标识符来代替字符串,在程序中出现宏名的位置,经过编译器的处理,被替换成对应的宏字符串,称为宏展开。标识符又称为宏名,通常用大写字母来表示,字符串称为宏体,一般是常数、关键词、语句、表达式等,也可以是空白,末尾不用分号。宏名的有效范围是从定义命令开始到程序结束,通常写在程序的开头,比如#define PI 3.1415926 根据源程序中出现PI用3.1415926来替换
#include <stdio.h>
#define PI 3.1415926
int main()
{
float r = 6;
float l,s,v;
l = 2.0 * PI * r;
s = PI*r*r;
v = 4.0/3*PI*r*r*r;
printf("r = %.2f\nl = %.2f\ns = %.2f\nv = %.2f\n",r,l,s,v);
}
宏展开只是简单的用定义的宏体替换宏名,由于是替换,所以宏定义中有无圆括号效果是不同的
比如
如果没有括号那么S将会被替换成80+40*80 很明显是不对的,所以需要用圆括号
另外在printf内,双引号中的LWS没有被替换,仅替换不在双引号以内的,制作字符串替换,并不会分配和占用内存。
带参数的宏定义
#define 标识符(形参表) 字符串
其中字符串包含形参参数,一般为表达式,也可以包括宏名和函数。使用带参宏时候,一定要注意要用实参替换形参。
宏展开通过宏体替换宏名(直接置换宏定义命令中相应的形参字符串,非形参字符保持不变)
#define V(l,w,h) l*w*h
...
VOLUME = v(4,2,8);
经过宏展开之后,赋值语句为4*2*8 按照宏定义的形参表的顺序从左向右进行置换,对于非形参字符*保留
带参数的宏定义中也可以引用已定义的宏定义
#define PI 3.1415926
#define S(r) PI*r*r
#define V(r) 4.0/3*S(r)*r
预处理是对每个宏名进行展开替换,直到程序中不再有宏名为止,我们来试着宏展开一下
假设V(3) = 4.0/3*S(3)*3
V(3) = 4.0/3*PI*3*3*3
V(3) = 4.0/3*3.1415926*3*3*3
宏替换中的实参广义上是一个字符串,一般为常量、变量或表达式。所以V的实参可以为(3*a)等
当然也可以用函数定义,带参数的宏和函数虽有很多相似之处,但二者在本质是不一样的。
- 函数调用需要分配内存和存储单元。而宏替换是在编译时进行的,仅仅进行替换 例如:#define sqr(x) (x)*(x) 在调用时有y=sqr(a+b);宏展开时候,直接用a+b替换x的值,函数的形参和实参要求类型兼容,而宏定义只是进行符号的替换。
- 函数调用占用程序运行时间,宏展开占用编译时间
- 参数和宏名之间没有空格,如果有空格,宏名会被定义为一个符号常量
- 如果宏展开后根据优先级可能会有误解,则需要在宏定义时候加上圆括号
解除宏定义
接触宏定义
作用:限定宏定义的作用域在某一个范围内,可以用#undef 命令来解除已有的宏定义
格式:#undef 宏名
#define MAX 100
…
#undef MAX
使得MAX在undef之前有效,之后便不再有效
重新宏定义
undef的另一个作用是重新进行宏定义,C语言中宏不能重复定义,即程序中不能使用同名的宏。若要重新定义,需先解除已有定义,再进行新的定义
文件包含
格式:#include<文件名> 或 #include “文件名”
<>会先在C语言库函数中查找 “”会先在本地目录查找,找不到再到库函数中去找,一次只能包含一个文件,在编译预处理时,文件包含命令行被包含进来的文件替换,成为源文件的一部分,与其他源文件一起参加编译。
条件编译
一般情况下,源程序中的所有语句都参加编译,但是我们有时会需要满足某种条件时才被编译。
条件编译命令格式
#ifdef 标识符
程序段1
#else
程序段2
#endif
若标识符已被定义过,则编译程序1否则编译程序2
#if 标识符
程序段1
#else
程序段2
#endif
若指定表达式的值为真,则程序段1参加编译,否则程序段2参加编译
#ifndef
程序段1
#else
程序段2
#endif
若标识符未被定义,则编译程序段1,否则编译程序段2
网站标题:CV鼻祖洋芋
原创文章,作者:locus,如若转载,请注明出处:https://blog.cvpotato.cn/forward-code/c-2/171/
本博客所发布的内容,部分为原创文章,转载注明来源,网络转载文章如有侵权请联系站长!