C语言中带参数的宏
带参数的宏定义有如下的格式:
【#define 指令----带参数的宏】 #define 标识符(x1,x2,……,xn)
其中 x1,x2,……xn是标志符(宏的参数)
注意:在宏的名字和括号之间必修没有空格。
如果有空格,预处理会认为是在定义一个简单的宏,其中(x1,x2,……,xn)是替换列表的一部分
当预处理器遇到一个带参数的宏,会将定义存储起来以便以后使用。在后面的程序中,如果任何地方出现了标识符(y1,y2……,yn)格式的宏调用(其中y1,y2, ……yn是一些列标记),预处理器会使用替换列表替代,并使用yi替换xi
e.g. 假如我们定义了如下的宏:
#define MAX(x,y) ((x)>(y) ? (x) : (y)) #define IS_EVEN(n) ((n)%2==0)
下面的例子是一个更加复杂的宏:
#define TOUPPER(c) ('a'<=(c) && (c)<='z' ? (c)-'a'+'A' : (c))
带参数的宏可以包含空的参数列表,如下所示:
#define getchar() getc(stdin)
空的参数列表不是一定确实需要,但可以使getchar更像一个函数
使用带参数的宏替代实际的函数有两个优点:
- 程序可能会稍微快些。一个函数调用在执行时通常会有些额外开销----存储上下文信息、复制参数的值等。而一个宏的调用则没有这些运行开销
- 宏会更“通用”。与函数的参数不同,宏的参数没有类型。因此,只要预处理后的程序依然合法的,宏可以接受任何类型的参数。 e.g.我们可以使用MAX宏从两个数中选出较大的一个,数的类型可以是:int,long int,float,double等等
- 编译后的代码通常会变大。每一处宏调用都会导致插入宏的替换列表,由此导致程序源代码增加(因此编译后的代码变大)。宏使用得越频繁,这种效果就越明显。当宏调用嵌套时,这个问题会相互叠加从而使程序更加复杂。e.g. n=MAX(i,MAX(j,k));
下面是预处理后的这条语句:
n=((i)>(((j)>(k)?(j):(k)))?(i):(((j)>(k)?(j):(k))));
- 宏参数没有类型检查。
- 无法用一个指针来指向一个宏
- 宏可能会不止一次地计算它的参数。函数对它的参数只会计算一次,而宏可能会计算两次甚至更多。如果参数有副作用,多次计算参数的值可能会产生意外的结果
考虑下面的例子,其中MAX的一个参数有副作用:
n=MAX(i++, j)
下面是这条语句在预处理之后的结果:
n=((i++) >(j)?(i++):(j));
带参数的宏不仅适用于模拟函数的调用,他们特别经常被作为模板,来处理我们经常要重复书写代码段:
e.g.我们可以使用
#define PRINT_INT(x) printf("%d\n",x);
使得PRINT_INT(x)代替每次使用的printf("%d\n",x);
转自http://www.cnblogs.com/cpoint/p/3367386.html
C语言中带参数的宏的更多相关文章
- C语言:带参数的宏与函数的区别
带参数的宏和函数很相似,但有本质上的区别:宏展开仅仅是字符串的替换,不会对表达式进行计算:宏在编译之前就被处理掉了,它没有机会参与编译,也不会占用内存.而函数是一段可以重复使用的代码,会被编译,会给它 ...
- 编译预处理 -- 带参数的宏定义--【sky原创】
原文:编译预处理 -- 带参数的宏定义--[sky原创] 如有转载请注明出处 编译预处理 -- 带参数的宏定义 前面为输出文件,后面为输入文件 gcc -E -o test.i test.c ...
- C语言中可变参数的函数(三个点,“...”)
C语言中可变参数的函数(三个点,“...”) 本文主要介绍va_start和va_end的使用及原理. 在以前的一篇帖子Format MessageBox 详解中曾使用到va_start和va_end ...
- c语言中函数参数入栈的顺序是什么?为什么
看到面试题C语言中函数参数的入栈顺序如何? 自己不知道,边上网找资料.下面是详细解释 #include <stdio.h> void foo(int x, int y, int z){ ...
- C语言中可变参数的用法
原文地址: http://blog.csdn.net/wooin/archive/2006/04/29/697106.aspx 我们在C语言编程中会遇到一些参数个数可变的函数,例如printf() ...
- C语言中可变参数的使用
在C语言程序编写中我们使用最多的函数一定包括printf以及很多类似的变形体.这个函数包含在C库函数中,定义为 int printf( const char* format, ...); 除了一个格式 ...
- C语言中可变参数的原理——printf()函数
函数原型: int printf(const char *format[,argument]...) 返 回 值: 成功则返回实际输出的字符数,失败返回-1. 函数说明: 使用过C语言的人所再熟悉不过 ...
- Python中带参数的装饰器
装饰器本身是用来是为一个函数是实现新的功能,并且不改变原函数的代码以及调用方式. 遇到这样一种问题: 众多函数调用了你写的装饰器,但客户有需求说,我想实现我可以随之控制装饰器是否生效. 那你就不可能在 ...
- Java中带参数的方法和JavaScript中带参数的函数有什么不同?
javascript是动态语言,是弱类型语言,其参数的使用很灵活:java则是强类型语言,参数的类型必须明确的
随机推荐
- Ubuntu 10.04 安装Qt4.8.1 源码后字体模糊的问题
Ubuntu 10.04 安装QT4.8.1 源码后字体模糊的问题. 附加解决 QT SDK 4.8.1 链接失败的问题 Ubuntu 10.04 编译QT源码后,编译程序,运行后IPA字体无法正常显 ...
- python 实现一个双色球生成程序
最近学习Python的Random函数,就顺手写一个随机数的双色球程序,开发环境:python2.7 , 附上源代码如下: # _*_ coding:utf- _*_ import random qi ...
- php log类
个人抽离出来一个超级简易但是实用的代码段 public static function WriteLog($msg,$module = null,$logLevel = "DEBUG&quo ...
- mysql-5.7 innodb_buffer_pool刷新机制详解
一.innodb的脏页刷新机制说明: 1.当innodb中的脏页比例超过innodb_max_dirty_pages_pct_lwm的值时,这个时候innodb就会开始刷新脏页到磁盘. 2.当inno ...
- Spring Bean的生命周期详解(转)
Spring作为当前Java最流行.最强大的轻量级框架,受到了程序员的热烈欢迎.准确的了解Spring Bean的生命周期是非常必要的.我们通常使用ApplicationContext作为Spring ...
- 进程间通信(java)--队列
前言: 在新增的Concurrent包中,BlockingQueue很好的解决了多线程中,如何高效安全“传输”数据的问题.通过这些高效并且线程安全的队列类,为我们快速搭建高质量的多线程程序带来极大的便 ...
- [转]WCF类型共享技巧
调用过WCF服务的同学可能都会遇到这样的问题,同一个实体类型,不同的服务Visual Studio生成了不同的版本,例如Service1.User和Service2.User,对于C#来说,这是两个不 ...
- STL_算法_查找算法(lower_bound、upper_bound、equal_range)
C++ Primer 学习中. .. 简单记录下我的学习过程 (代码为主) //全部容器适用(O(log(n))) 已序区间查找算法 lower_bound() //找第一个符合的 ...
- mysqldump 备份某张表 Warning: A partial dump from a server that has GTIDs will by default include the GTIDs of all transactions,
[root@NB ok]# mysqldump -uemove -h xx.xx.xx.xx -P9906 DBname t_name -p >2t_tname.sqlWarning: A pa ...
- .NET Garbage-Collectors
http://mattwarren.org/tags/#Garbage-Collectors https://github.com/dotnet/coreclr/issues https://lldb ...