龙空技术网

C语言中的预处理基本知识

快乐每日数学 396

前言:

今天咱们对“编译原理 预处理”大约比较着重,同学们都想要分析一些“编译原理 预处理”的相关内容。那么小编也在网络上汇集了一些有关“编译原理 预处理””的相关知识,希望大家能喜欢,同学们快快来了解一下吧!

预处理是C语言特有的功能,如:宏定义、条件编译等等,好处嘛,很多,如程序可读性好、便于修改以及移植与调试等,好处这么多,那我们今天就介绍一下。

一、宏定义:

宏定义指令使用:#define,它用来定义一个可替换的宏,分为不带参数的宏定义跟不带参数的宏定义,我们一个一个介绍。

①、不带参数宏定义:

首先看不带参数的宏定义一般形式:

#define 宏名 字符串

说明:加上#符就代表这是一条预处理指令。

宏名当然就是一个标识符。

字符串这里可以是常量、格式字符串,当然也可以是表达式。

如:#define PI 3.14,其作用就是在编译预处理时,只要在程序中遇到PI,那么就直接用3.14代替。用此有一个好处,就是想要改变程序中PI的值时,只需要直接改变预处理语句后面PI的值,那么整个程序PI的值就会改变。

还有一点就是,宏名要大写,以区别其他变量。

当然了,当一个宏名定以后也可以成为其他宏名定义的一部分,如#define r 2,#define C 2*PI*r。

宏替换不仅可以代替一般字符串,更可以替换关键字,如#define P printf,此语句用P替换关键字printf。如printf("i love you!"),可以换为P("i love you!"),这两句是等效的。

注意:如果在字符串中包含宏名,那么是不会进行替换的。如#define TEXT "love",char *pc="i TEXT you!";printf("%s",pc)。最后输出不会是i love you!,而是输出i TEXT you!。

还有一点需要注意的是,不能将宏定义分散到程序当中,必须将其放到开始处或独立文件中,这样的有效范围为从定义处到源文件结束。但是有时我们并不需要有效范围到源文件末尾,因此,我们就可以使用#undef指令来提前结束有效范围,如printf(TEXT);#undef TEXT;后面的语句就不能再用TEXT了。

还有宏定义只是用于预处理命令,它只做字符替换,不会分配内存空间,这一点跟变量有所不同。

②、带参数的宏定义:

带参数的宏定义一般形式如下:#define 宏名(参数列表) 字符串,当然了,还是举一个例子吧:

#define M(a,b) ((a)*(b))

printf("%d",M(3,4));

结果为12,从结果可以看出,带参数的宏定义不仅仅是字符串替换还要进行参数替换。

注意:上面看到给参数加上括号并且还在整个表达式外都加上了括号,为什么这样呢?其实举一个简单例子,如果不在参数外加括号,如#define M(a,b) (a*b)

如果这样printf("%d",M(3,3+4));那么结果是什么呢?结果是3*3+4=13,而我们想要的结果为21,所以最好把参数用括号括起来。

还有为啥还要加外括号呢?其实在举一个例子,如#define M(a,b) (a)+(b);printf("%d",2*M(3,4)),结果为2*3+4=10,但是这并不是我们想要的结果14,所以要加上外括号。

还有在宏定义中,形参并不分配内存空间,因此不需要指定类型。

还有宏名跟参数列表括号之间不能用空格,因为宏定义将会把宏名空格以后的字符都作为替代字符串的一部分。

二、#include指令:

此指令的作用是:将另一源文件的全部内容都包含都本文件当中,有两种表示形式#include<stdio.h>、#include"stdio.h"两种表示形式有区别,第一种,系统会直接在C库函数头文件所在的目录中查找要包含的文件,第二种是在用户当前目录中查找,如果找不到才回到C库函数头文件所在的目录中查找要包含的文件,当然双引号中也可以指定文件所在的路径。

常用在文件头部被包含的文件成为标题文件或者头部文件,一般以.h为后缀。

常把宏定义、结构、联合、枚举声明、全局变量声明、外部函数声明等放到.h的文件中。

三、条件编译:

一般的情况下,源程序中所有的代码都会参加编译,但有时我们希望对一部分内容在满足一定条件下才会进行编译,这个时候条件编译就产生了作用。

①、#if命令:

一般形式为:

#if 常量表达式

语句块

#endif

如果为真那么后面的程序段将会被编译,如果为假,则跳过不编译。

当然了,还有#else作用为#if的另一种选择,跟else想近。

前面有个条件语句else if。当然条件编译语句也有类似的#elif,一般形式为:

#if 表达式1

语句块;

#elif 表达式2

语句块;

……

#elif 表达式n

语句块;

#endif

当然你可能不太理解,用条件语句不是也可以实现吗?也许你不理解编译的概念,条件语句中的什么if else if不管后面表达式真假,都会被编译,只是在执行过程中选择执行或不执行,举一个简单例子:

#include<stdio.h>

int main(){

int a=10;

#if a>10

ashduehejfj;

#endif

};

上面的代码你会发现,编译通过并没有报错,之间根本就是乱写的,居然还能通过,那是因为中间语句不被编译,所以能通过,如果换成if那么就会报错。

②、#ifdef跟#ifndef指令:

这两个用于判断一个宏替换是否被定义,#ifdef用于如果被定义则编译后面的语句块,#ifndef用于如果没有定义则编译后面的语句块,其一般形式为:

#ifdef 宏替换名

语句块;

#endif

#ifndef 宏替换名

语句块;

#endif

当然了,也可以跟#else,一般形式为:

#ifdef(#ifndef) 宏替换名

语句块;

#else

语句块;

#endif

③、#undef命令:

其一般形式为:#undef 宏替换名,用于提前终止宏替换名的作用范围,上面讲解过。

④、#line命令:

#line一般形式如下:#line 行号[文件名]。

其中行号为任意正数,_LINE_用于存放当前正在编译的行数,_FILE_存放当前编译的文件名。如要得到当前行数:printf("%d",_LINE_);。

上面就是检验介绍一些预处理的基本知识。希望对你们有用。

标签: #编译原理 预处理