//本文为转载,具体出处已经找不到了。这里引用为了知识传播。感谢原作者。

C语言允许宏带有参数。在宏定义中的参数称为形式参数,在宏调用中的参数称为实际参数,这点和函数有些类似。就像把函数的实参传递给形参。

对带参数的宏,在调用中,不仅要宏展开,而且要用实参去代换形参。

带参宏定义的一般形式为:
#define 宏名(形参列表) 字符串
在字符串中含有各个形参。

带参宏调用的一般形式为:
宏名(实参列表);
例如:

 # define M(y) y*y+3*y  //宏定义
// Code
k=M(5);  //宏调用

在宏调用时,用实参5去代替形参y,经预处理宏展开后的语句为k=5*5+3*5。

【示例】输出两个数中较大的数。

    #include <stdio.h>#define MAX(a,b) (a>b) ? a : bint main(){int x , y, max;printf("input two numbers: ");scanf("%d %d", &x, &y);max = MAX(x, y);printf("max=%d\n", max);return 0;}

运行结果:

input two numbers: 10 20
max=20

程序第2行进行了带参宏定义,用宏名MAX表示条件表达式(a>b) ? a : b,形参a、b均出现在条件表达式中。程序第7行max=MAX(x, y)为宏调用,实参 x、y 将代换形参a、b。宏展开后该语句为:

max=(x>y) ? x : y;

对带参宏定义的说明
1) 带参宏定义中,形参之间可以出现空格,但是宏名和形参列表之间不能有空格出现。例如把:#define MAX(a,b) (a>b)?a:b

#define MAX (a,b) (a>b)?a:b

将被认为是无参宏定义,宏名MAX代表字符串(a,b) (a>b)?a:b。宏展开时,宏调用语句:

max=MAX(x,y);

将变为:

max=(a,b)(a>b)?a:b(x,y);

这显然是错误的。

2) 在带参宏定义中,不会为形式参数分配内存,因此不必指明数据类型。而在宏调用中,实参包含了具体的数据,要用它们去代换形参,因此必须指明数据类型。

这一点和函数是不同的:在函数中,形参和实参是两个不同的变量,都有自己的作用域,调用时要把实参的值传递给形参;而在带参数的宏中,只是符号的替换,不存在值传递的问题。

【示例】输入 n,输出 (n+1)^2 的值。

    #include <stdio.h>#define SQ(y) (y)*(y)int main(){int a, sq;printf("input a number: ");scanf("%d", &a);sq = SQ(a+1);printf("sq=%d\n", sq);return 0;}

运行结果:

input a number: 9
sq=100

第2行为宏定义,形参为 y。第7行宏调用中实参为 a+1,是一个表达式,在宏展开时,用 a+1 代换 y,再用 (y)*(y) 代换 SQ,得到如下语句:

sq=(a+1)*(a+1);

这与函数的调用是不同的,函数调用时要把实参表达式的值求出来再传递给形参,而宏展开中对实参表达式不作计算,直接按照原样替换。

3) 在宏定义中,字符串内的形参通常要用括号括起来以避免出错。例如上面的宏定义中 (y)*(y) 表达式的 y 都用括号括起来,因此结果是正确的。如果去掉括号,把程序改为以下形式:

    #include <stdio.h>#define SQ(y) y*yint main(){int a, sq;printf("input a number: ");scanf("%d", &a);sq = SQ(a+1);printf("sq=%d\n", sq);return 0;}

运行结果为:
input a number: 9
sq=19
同样输入9,但结果却是不一样的。问题在哪里呢?这是由于替换只作符号替换而不作其它处理而造成的。宏替换后将得到以下语句:

sq=a+1*a+1;

由于a为9故sq的值为19。这显然与题意相违,因此参数两边的括号是不能少的。即使在参数两边加括号还是不够的,请看下面程序:

    #include <stdio.h>#define SQ(y) (y)*(y)int main(){int a,sq;printf("input a number: ");scanf("%d", &a);sq = 200 / SQ(a+1);printf("sq=%d\n", sq);return 0;}

与前面的代码相比,只是把宏调用语句改为:

sq=200/SQ(a+1);

运行程序后,如果仍然输入 9,那么我们希望的结果为 2。但实际情况并非如此:

input a number: 9
sq=200

为什么会得这样的结果呢?分析宏调用语句,在宏展开之后变为:

sq=200/(a+1)*(a+1);

a 为 9 时,由于“/”和“”运算符优先级和结合性相同,所以先计算 200/(9+1),结果为 20,再计算 20(9+1),最后得到 200。

为了得到正确答案,应该在宏定义中的整个字符串外加括号:

    #include <stdio.h>#define SQ(y) ((y)*(y))int main(){int a,sq;printf("input a number: ");scanf("%d", &a);sq = 200 / SQ(a+1);printf("sq=%d\n", sq);return 0;}

由此可见,对于带参宏定义不仅要在参数两侧加括号,还应该在整个字符串外加括号。

4.6宏定义之带参宏相关推荐

  1. 宏定义(无参宏定义和带参宏定义)

    宏定义是比较常用的预处理指令,即使用"标识符"来表示"替换列表"中的内容.标识符称为宏名,在预处理过程中,预处理器会把源程序中所有宏名,替换成宏定义中替换列表中 ...

  2. 【C语言】宏定义和带参宏定义

    宏定义是在编程中经常使用的一个模块,其优点在于当写的代码量比较大的时候方便修改检查,可以做到改一变"百". 一.宏定义 宏定义是用宏名来表示一个字符串,在宏展开时又以该字符串取代宏 ...

  3. 05c语言——宏定义、带参宏、带参宏函数

    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 一.宏定义 1.使用规则 2.注意 二.带参宏 1.定义 2.注意 三.带参函数 1.带参函数的宏与带参宏的区别 2.带参宏 ...

  4. 宏定义有无参数宏定义和带参数宏定义两种

    宏定义有无参数宏定义和带参数宏定义两种. 无参数的宏定义的一般形式为 # define 标识符 字符序列 其中# define之后的标识符称为宏定义名(简称宏名),要求宏名与字符序列之间用空格符分隔. ...

  5. 带参宏定义和带参函数的区别

    在带参宏定义中,不会为形式参数分配内存,因此不必指明数据类型.而在宏调用中,实参包含了具体的数据,要用它们去代换形参,因此必须指明数据类型. 这一点和函数是不同的:在函数中,形参和实参是两个不同的变量 ...

  6. 【C语言】宏定义(不带参数的宏定义和带参数的宏定义)

    目录 一.不带参数的宏定义 1.定义 2.#undef 指令取消宏定义 二.带参数的宏定义 1.定义 2.宏定义参数替换的注意事项 三.带参数的宏定义和带参函数的区别 一.不带参数的宏定义 1.定义 ...

  7. ACMNO.30 C语言-宏交换 定义一个带参的宏,使两个参数的值互换,并写出程序,输入两个数作为使用宏时的实参。输出已交换后的两个值。

    题目描述 定义一个带参的宏,使两个参数的值互换,并写出程序,输入两个数作为使用宏时的实参.输出已交换后的两个值. 输入 两个数,空格隔开 输出 交换后的两个数,空格隔开 样例输入 1 2 样例输出 2 ...

  8. 带参宏和带参函数的比较(C语言)

    例:分别通过宏定义和函数方式求a和b的乘积 #include<stdio.h> #define mult_macro(a,b) a*b int mult_fun(int a, int b) ...

  9. 定义一个有参宏判断一个字符是否在0~9之间

    <程序设计基础-c语言>杨莉 刘鸿翔 ISBN-978-7-03-032903-5 p241 习题7 12.定义一个有参宏IS_DIGIT(ch),当ch是一个0~9的字符时,返回1,否则 ...

最新文章

  1. 什么才是真正的L3自动驾驶?
  2. 【超详细】手把手教你使用YOLOX进行物体检测(附数据集)
  3. 【Netty】从 BIO、NIO 聊到 Netty
  4. MyBatis学习总结(三)——优化MyBatis配置文件中的配置
  5. golang中的TestMain
  6. General-purpose and introductory examples for the scikit.
  7. 随笔(一)-- Jupyter Notebook如何切换主题、更改字体大小
  8. 在MATLAB function中可变的变量数据类型
  9. Tomcat【环境搭建 02】Web端403 Access Denied You are not authorized to view this page解决方法(Tomcat 10.2.12 版本)
  10. 问题 C: 完美的数(思维)
  11. 【移动开发】安卓Lab2(02)
  12. 最强新一代消息系统,没有之一,不接受反驳!
  13. rstudio 导出结果_RStudio如何完美导出包含中文的图
  14. 17、【 商品管理模块开发】——后台商品图片的springmvc和富文本上传以及ftp文件服务器的开发...
  15. 剑指offer编程题Java实现——面试题3二维数组中的查找
  16. 安装linux到服务器配置,CentOS 6.3 服务器安装配置
  17. Linux0基础深度解析shell简介01
  18. 因DataTable的字段值为DBNull引发的异常
  19. react native+typescript创建移动端项目-(慕课网喜马拉雅项目笔记)-(一,项目的初始化配置)
  20. 动态规划实战1-leetcode 983.Minimum Cost For Tickets

热门文章

  1. 2020,为抖音微信打工的一年
  2. 【python】wallhaven.cc随机壁纸页面小爬虫
  3. 找资源的网址——总结笔记二
  4. 显示两个版本间的差异
  5. 搜索专题小结:迭代加深搜索
  6. wandb不可缺少的机器学习分析工具
  7. 计算机微机原理pdf,《微机原理与接口技术》作业.pdf
  8. Multiple comparison
  9. NAT穿透技术详解(udp打洞精髓附代码)
  10. svn代码量统计工具