ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

c语言预处理

c语言预处理 第十七章 联合体和枚举第十八章 动态内存管理第十九章 文件操作第二十章编译和链接文章目录前言一、预处理是什么二、使用1.预处理符号2.#define定义常量3.#define定义宏4.宏替换的规则5.宏函数的对比6.#和##总结前言随着嵌入式开发和系统编程的不断发展C语言这门基础语言也越来越重要很多人都开始学习C语言本文就介绍了C语言预处理的核心内容。一、预处理是什么预处理是C语言编译过程中的第一阶段它在编译器正式编译之前对源代码进行文本层面的处理。预处理指令以#开头主要包括宏定义、文件包含、条件编译等。二、使用1.预处理符号c语言设置了一些预处理符号是可以直接使用的例如__FILE__//进行编译的源文件__LINE__//文件当前的行号__DATE__//文件被编译的日期__TIME__//文件被编译的时间__STDC__//如果编译器遵循ANSI C其值为1否则未定义2.#define定义常量有时候我们会遇到需要反复使用某个值的场景为了方便我们可以把它定义为常量。基本语法为#define name stuff#defineMAX1000//定义常量MAX 1000#defineregregister//为register这个关键字//创建一个简短的名字#definedo_foreverwhile(1)//用更形象的符号替换实现#defineCASEbreak;case//写case语句的时候自动把// break加上//如果stuff过长可以在每行后面加上反斜杠分成几行写#defineDEBUG_PRINTprintf(file:%s\tline:%d\t\ date%s\ttime:%s\n,\__FILE__,__LINE__,\__DATE__,__TIME__)在用define定义的时候最好不要再后面加上分号否则在某些语句下面可能会出现错误。例如#defineMAX1000;if(...)maxMAX;这里因为没有大括号的时候if后面只能用一条语句如果有两条就会报错。3.#define定义宏#define还可以把参数替换到文本中这种实现通常称为宏。#define name(parament-list) stuff其中parament-list是 一个由逗号隔开的符号表它们可能出现在stuff中。参数的左括号必须要与name紧邻如果之间有空白存在参数列表就会把这个解释为stuff的一部分。例子#defineSQUARE(x)x*x这个宏接收参数x如果你把SQUARE5放置在程序中预处理器就会把他替换成表达式5*5但是这个宏存在问题inta5;SQUARE(a1);我们这里想着的是把6传进去但是实际上替换之后得到的是a1*a1运算的顺序变了所以正确的写法应该是在后面的宏定义加上括号这样就能达到我们想要的效果。#define SQUARE(x) (x)*(x)还有一种宏定义会出现问题#defineDOUBLE(x)(x)(x)inta5;intnum10*DOUBLE(a)这里我们预期的结果是100但是运行之后发现输出结果是55我们把它替换后发现得到的代码是10*55运算顺序是乘法先算为了解决这个问题我们要在外面再加一个括号。#define DOUBLE(x) ((x)(x))通过上面的例子我们可以得出结论对于数值表达式进行求值的宏定义都应该加上括号以避免运算的时候参数中的操作符或者临近操作符之间不可预料的相互作用。某些宏参数还会带有副作用如果宏参数在宏定义中出现超过一次并且宏参数带有副作用那么在使用宏的时候就可能出现危险导致不可预测的后果。副作用是参数求值的时候出现的永久性效果。#defineMAX(a,b)((a)(b)?(a):(b))x4;y5;zMAX(x,y);这里整体替换如下z ((x)(y)?(x):(y));此时x等于5y等于7z等于6并不能得到我们想要的结果如果想要得到正确的结果我们只需要把x和y改成1即可就没有副作用了。4.宏替换的规则在程序中扩展#define定义符号和宏的时候需要涉及几个步骤1.在调用宏的时候首先对参数进行检查查看是否包含任何由#define定义的符号如果有就仙贝替换。2.替换文本插入到程序原来文本的位置对于宏参数名被他们的值所替换。3。最后再次对结果文件进行扫描查看是否包含由#define定义的符号如果有则重复上面的过程。注意1.宏参数和#define定义中可以出现其他由#define定义的符号但是对于宏不能出现递归。2.当预处理器搜索#define定义的符号的时候字符串常量的内容不被搜索。5.宏函数的对比宏通常由于执行简单的运算比如在两个数中找到一个更大的数。对比函数来说宏在程序的规模和速度方面会更胜一筹而且宏参数与类型无关而函数需要在类型合适的表达式中使用。当然宏也有他的弊端1.使用宏的时候如果宏很长就会大幅度增加程序的长度。2.宏无法调试3.宏由于类型无关因此也不够严谨4.宏会带来运算符优先级的问题下面是宏与函数的对比表格对比项宏函数代码长度每次使用时都会插入宏代码可能使程序变长函数代码只保存一份每次调用只增加调用开销执行速度预处理时直接替换无调用开销速度更快有函数调用和返回的开销速度稍慢操作符优先级容易因缺少括号产生优先级问题函数参数在调用时求值优先级由函数内部决定参数类型与类型无关任何类型都可传入需要与函数参数类型匹配副作用参数可能被多次求值产生不可预测的副作用参数只在调用时求值一次无副作用问题调试宏在预处理阶段已替换无法调试函数可以设置断点方便调试递归宏不能递归函数支持递归6.#和###运算符能将宏参数转化成字符串的字面量仅允许出现在带参数的宏的替换列表中。#运算符所执行的操作可以理解为“字符串化”。假如我们有一个变量a10当我们想要打印出“the value of a is 10.”我们就可以这样写#define PRINT(n) printf(“the value of”#nis %d.,n)当我们调用PRINTa的时候就会把n替换成a#n替换成#a就转换成“a”##可以把位于两边的符号合成一个符号被称为记号粘连。但是这个东西基本上用不到。最多是在宏定义生成函数的时候通过##生成函数名。例如#defineGENERIC_MAX(type)type type##_max(type x,type y){return(xy?x:y);}一般我们约定宏名全部大写函数名不全部大写来区分宏和函数。使用#undef可以移除一个宏定义总结例如以上就是今天要讲的内容本文仅仅简单介绍了C语言预处理的使用而预处理提供了大量能使我们快速便捷地处理代码的功能和方法如宏定义、文件包含、条件编译等。
返回列表