带参数的宏定义有如下的格式:

【#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语言中带参数的宏的更多相关文章

  1. C语言:带参数的宏与函数的区别

    带参数的宏和函数很相似,但有本质上的区别:宏展开仅仅是字符串的替换,不会对表达式进行计算:宏在编译之前就被处理掉了,它没有机会参与编译,也不会占用内存.而函数是一段可以重复使用的代码,会被编译,会给它 ...

  2. 编译预处理 -- 带参数的宏定义--【sky原创】

    原文:编译预处理 -- 带参数的宏定义--[sky原创] 如有转载请注明出处   编译预处理  --  带参数的宏定义 前面为输出文件,后面为输入文件 gcc -E -o test.i test.c ...

  3. C语言中可变参数的函数(三个点,“...”)

    C语言中可变参数的函数(三个点,“...”) 本文主要介绍va_start和va_end的使用及原理. 在以前的一篇帖子Format MessageBox 详解中曾使用到va_start和va_end ...

  4. c语言中函数参数入栈的顺序是什么?为什么

    看到面试题C语言中函数参数的入栈顺序如何? 自己不知道,边上网找资料.下面是详细解释 #include <stdio.h> void foo(int x, int y, int z){   ...

  5. C语言中可变参数的用法

    原文地址: http://blog.csdn.net/wooin/archive/2006/04/29/697106.aspx   我们在C语言编程中会遇到一些参数个数可变的函数,例如printf() ...

  6. C语言中可变参数的使用

    在C语言程序编写中我们使用最多的函数一定包括printf以及很多类似的变形体.这个函数包含在C库函数中,定义为 int printf( const char* format, ...); 除了一个格式 ...

  7. C语言中可变参数的原理——printf()函数

    函数原型: int printf(const char *format[,argument]...) 返 回 值: 成功则返回实际输出的字符数,失败返回-1. 函数说明: 使用过C语言的人所再熟悉不过 ...

  8. Python中带参数的装饰器

    装饰器本身是用来是为一个函数是实现新的功能,并且不改变原函数的代码以及调用方式. 遇到这样一种问题: 众多函数调用了你写的装饰器,但客户有需求说,我想实现我可以随之控制装饰器是否生效. 那你就不可能在 ...

  9. Java中带参数的方法和JavaScript中带参数的函数有什么不同?

    javascript是动态语言,是弱类型语言,其参数的使用很灵活:java则是强类型语言,参数的类型必须明确的

随机推荐

  1. go语言学习 ---iota

    iota iota,特殊常量,可以认为是一个可以被编译器修改的常量. iota 在 const关键字出现时将被重置为 0(const 内部的第一行之前),const 中每新增一行常量声明将使 iota ...

  2. FA_会计中的折旧方式的种类(概念)

    2014-06-08 Created By BaoXinjian

  3. Android 报错:Conversion to Dalvik format failed: Unable to execute dex: java.nio.BufferOverflowException. Check the Eclipse log for stack trace.

    在android高版本开发环境(sdk 4.4)导入低版本(sdk 3.0)的工程时编译报错,报错信息如:Conversion to Dalvik format failed: Unable to e ...

  4. 最短路径 - 弗洛伊德(Floyd)算法

    为了能讲明白弗洛伊德(Floyd)算法的主要思想,我们先来看最简单的案例.图7-7-12的左图是一个简单的3个顶点的连通网图. 我们先定义两个二维数组D[3][3]和P[3][3], D代表顶点与顶点 ...

  5. Ext4文件系统架构分析(三)

    ioctl源码分析之交换两个文件的物理extents 1. 交换两个文件的extents Ext4 的EXT4_IOC_MOVE_EXT命令用于交换两个文件的extents,实际上是交换两个文件的对应 ...

  6. Python2 unichr() 函数

    描述 unichr() 函数 和 chr()函数功能基本一样, 只不过是返回 unicode 的字符. 语法 以下是 unichr() 方法的语法: unichr(i) 参数 i -- 可以是10进制 ...

  7. android侧滑效果,SlidingMenu配置

    最近开始做点东西,需要用到android activity侧滑的效果.感觉配置起来还是有点小麻烦,总结一下以便回顾. 需要的东西: 1.SlidingMenu项目:点击打开链接 2.ActionBar ...

  8. 免费申请 Github 私有仓库--学生和教育人士的福利

    免费申请 Github 私有仓库 -学生和教育人士的福利 Github 是全球知名的软件项目托管网站.在 Github 创建私有仓库是需要收费的,收费方案有多种,费用最小的方案是每月 7 美元的“微型 ...

  9. 成员函数的重载&amp;&amp;隐藏&amp;&amp;覆盖

    /* *成员函数的重载,覆盖,隐藏 *重载: *1.同样的范围(在同一个类中) *2.函数名同样 *3.參数不同 *4.virtualkeyword可有可无 *覆盖是指派生类覆盖基类的函数,特征是: ...

  10. [docker]docker0网络模型探究

    docker0网络模型step by step 将docker的ns软链到linux ns $ ln -s /var/run/docker/netns /var/run/netns 查看ns,无 $ ...