不带参数的宏定义一般形式是:#define宏名字符串例如:#definePI3.1415926其中,宏名用标识符表示,也就是前面讨论过的符号常量,上面示例中的PI就是宏名。正确使用“宏定义”的关键是宏调用时的“原样替换”。宏定义使用的简单示例。④宏定义不存在类型问题,它的参数也是无类型的。⑦宏定义允许嵌套。如:#defineN100#defineM2*N#defineK5+M⑧可以用#undef或不带替换字符串的宏定义终止宏定义的作用域。......
2025-09-30
带参数宏定义除了进行字符串替换外,还通过参数的代入实现更加复杂的宏代换功能,带参数宏定义的一般形式为:
#define 标识符(形参表) 表达式样式字符串
宏调用的格式为:
标识符(实参表)
带参数的宏调用时一般分为两个步骤。例如,对于宏定义:#define S(a,b)ab进行宏调用的形式为T=S(3,2);,第一步将宏换为T=ab;,第二步将实参代入换为T=32;。
使用带参数宏定义时,除了前面提到的使用宏定义预处理的注意事项外,还要注意下面几点:
①带参宏定义中,宏名和形参表之间不能有空格出现。
如:#define S(a,b) ab
如果误写为:#define S (a,b) ab,则将被认为是无参宏定义,宏名为S,字符串为(a,b) ab。
②带参宏定义中,形式参数不分配内存单元,因此不必作类型定义。(https://www.chuimin.cn)
③在宏定义中的形参是标识符,而宏调用中的实参可以是表达式。为了避免当实参是表达式时的替换错误,定义时应将用于替换字符串中的所有形参用圆括号括起来。请比较并区别下面两种形式。
在C程序中使用带参数宏代换时,特别需要注意宏代换和函数调用的区别:
①函数调用时,先求出实参表达式的值,然后代入形式参数。而带参数的宏对实参表达式不作计算直接照原样代换,只是进行简单的替换。
②函数调用是在程序运行时处理的,因为形参要分配临时的存储单元。而带参数宏的展开则是在编译前进行的,在展开时并不分配内存单元,不进行值的传递处理,也没有返回值的概念。
③带参数宏的形式参数与函数中的形式参数不同,它没有确定的数据类型。在宏调用时随着代入的实际参数数据类型的不同,其运算结果的类型随之而变。
在程序设计时,采用宏定义还是函数需要根据情况而定,有关函数的部分已经在前面章节介绍过,与函数比较,宏定义的好处是宏替换是在编译阶段进行的,不占运行时间。同时它也有缺点,宏定义在预处理时原地进行替换展开,一般会增加代码的长度;此外,宏调用时并没有参数类型的检查,有可能引起不可预料的程序设计错误。
【例9.3】 带参数宏调用替换问题的理解示例。
在阅读理解上面程序时最容易得到的错误结果是:t=3000。事实上,宏替换后得到的表达式为:t=Min(a+b,c+d)1000;→t=(a+b)<(c+d)?(a+b):(c+d)1000;,从预处理完成的语句可以看出,在条件表达式中,当(a+b)<(c+d)的结果是1(非0)时,表达式最后的1000与应该取得的值毫无关系。程序运行的正确结果为:t=3。
相关文章
不带参数的宏定义一般形式是:#define宏名字符串例如:#definePI3.1415926其中,宏名用标识符表示,也就是前面讨论过的符号常量,上面示例中的PI就是宏名。正确使用“宏定义”的关键是宏调用时的“原样替换”。宏定义使用的简单示例。④宏定义不存在类型问题,它的参数也是无类型的。⑦宏定义允许嵌套。如:#defineN100#defineM2*N#defineK5+M⑧可以用#undef或不带替换字符串的宏定义终止宏定义的作用域。......
2025-09-30
包括函数名的命名和类型说明、形式参数的类型说明、变量定义和语句。下面举例说明主函数和自定义函数。函数的定义是平行的,彼此相互独立,不能嵌套定义。函数的类型和函数返回值的类型应保持一致。以两个数求和为例,说明函数的定义。......
2025-09-30
不带参数的宏用指定标识符来代替一个字符串。其一般格式为:#define标识符 字符串例如:#define PI 3.1415926用标识符PI来表示3.1415926,这叫做宏定义。但多数人习惯把所有的宏定义都写在文件的前面虽然这不是必须的。一个宏定义后,就可以在程序中使用了,例如:这个函数返回圆的面积。这里的1、0与一般意义下的1、0形式上没有任何不同,不容易让人理解,有了宏,我们就可以很方便地解决这个问题了。......
2025-09-30
习惯把用typedef声明的类型名用大写字母表示,以便与系统提供的标准类型标识符区别。用tpyedef可以声明数组类型、字符串类型,使用比较方便。用typedef只是对已经存在的类型增加一个类型名,而没有创造新的类型。使用typedef有利于程序的通用与移植。有时程序会依赖于硬件特性,用typedef便于移植,例如,有的计算机系统int型数据占用2个字节,而另一些机器则占用4个字节。......
2025-09-30
一个函数直接或间接地调用自己,称为函数的递归调用。所以函数递归调用的实现必须依靠系统提供一个特殊部件(堆栈)存放未完成的操作,以保证当递归调用结束回溯时不会丢失任何应该执行而没有执行的操作。为了理解函数递归调用的特性,参照例5.9的程序讨论函数递归调用的执行过程,为了讨论方便为程序加上行号。函数递归调用示例。......
2025-09-30
掌握选择结构的程序设计思想。完整的源程序:提醒:以上程序也可将case 2换成default,思考一下为什么?项目3:运输公司对用户计算运费。根据距离s的取值范围不同,折扣也相应发生变化,因此该程序为选择结构的程序,可以使用if语句,也可以使用switch语句。在编写程序时,距离s取值区间两端的数据都是250的整数倍,因此,可以通过s/250的方法将区间转换成用整型数据来表达,以便使用switch语句编写程序。......
2025-09-30
图5.3指针变量指针变量本身也是变量,所以指针变量在使用之前也需要定义。为指针变量赋值的方法有两种:一种是定义后,使用赋值语句的方式;另外一种是定义的同时进行初始化方式。......
2025-09-30
C语言的最大特点是:功能强、使用方便灵活。由于这个“灵活”给程序的调试带来了许多不便,尤其对初学C语言的人来说,经常会出一些连自己都不知道错在哪里的错误。在C语言中大写字母和小写字母是两个不同的字符。C语言规定以’\0’作字符串结束标志,它是由系统自动加上的。当一个语句中使用多层括弧时常出现这类错误。main()C语言中对数组的定义或引用数组元素时必须用方括弧。......
2025-09-30
相关推荐