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

时间: 2024-10-18 05:48:11

C语言中带参数的宏的相关文章

c语言之带参数的宏定义

1.带参数的宏定义中,宏名和新参表之间不能有空格, 2.在带参数的宏定义中,形参参数不分配内存单元,因此不必作类型定义.而宏调用中的实参有具体值,要用它去代换形参,因此必须作类型说明. #include<stdio.h> #include<iostream> #define MAX(a,b) (a>b)?a:b int main() { int x, y, max; x = 2; y = 3; max = MAX(x,y); printf("%d\n",

C语言:带参数的宏定义

宏名的命名规范 1.全部大写有多个单词中间使用下划线隔开(常用) 2.以k开头的驼峰标识(不常用) 带参数的宏定义:把出现宏名地方都会把宏名后面小括号中的参数代入到宏后面的表达式中,然后进行替换 格式:#define 宏名(参数列表)  表达式 注意点:1.参数列表中没有类型 2.宏名与括号之间一定不要加空格 带参数的宏与函数的区别 1.函数有一个调用过程,会开辟新存储空间,需要花费一些开销的 2.宏仅仅是做一个替换的操作 使用场景: 1.当计算比较简单,参数比较少的时候使用宏,宏提高运算效率

sas宏(3)宏,调试宏,创建带参数的宏,理解符号表(全局宏与局部宏解析),宏条件运算符,在宏中进行运算

宏类似于c中的函数,传入指定参数后执行,并且宏内部可以包含data步程序和条件运算符号. 宏变量只是小小的变量....(by the way作用也很大) 1:宏的基本语法 如何创建一个简单的宏并使用? %macro prtlast; proc print data=&syslast (obs=5); title "Listing of &syslast data set"; run; %mend; %prtlast /*不要加分号,加了有可能出错*/ 宏创建过程中做了什

C语言带参数的宏

利用带参数的宏,可以加强封装,简化主体代码.(VC6控制台工程) 1 // 带参数的宏.cpp 2 // 看看带参数的宏是怎么玩的 3 4 //#include "stdafx.h" 注释掉这个头文件,同时在Project——setting——precompiled headers——选择“Not Use Precompiled Header”,能够避免compile出错 5 #include "stdio.h" 6 7 #define prt(cmd) (prin

不带参数的宏定义与带参数的宏定义

宏定义是C提供的三种预处理功能的其中一种,这三种预处理包括:宏定义.文件包含.条件编译 1.不带参数的宏定义: 宏定义又称为宏代换.宏替换,简称“宏”. 格式: #define 标识符 字符串 其中的标识符就是所谓的符号常量,也称为“宏名”. 预处理(预编译)工作也叫做宏展开:将宏名替换为字符串. 掌握"宏"概念的关键是“换”.一切以换为前提.做任何事情之前先要换,准确理解之前就要“换”. 即在对相关命令或语句的含义和功能作具体分析之前就要换: 例: #define PI 3.1415

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

C语言中可变参数的函数(三个点,"...") 本文主要介绍va_start和va_end的使用及原理. 在以前的一篇帖子Format MessageBox 详解中曾使用到va_start和va_end这两个宏,但对它们也只是泛泛的了解. 介绍这两个宏之前先看一下C中传递函数的参数时的用法和原理: 1.在C中,当我们无法列出传递函数的所有实参的类型和数目时,可以用省略号指定参数表 void foo(...); void foo(parm_list,...); 这种方式和我们以前认识的不大

编程题:带参数的宏定义来实现,求圆的周长和面积。

#include<stdio.h> #define PI 3.14159 #define L(r) 2*PI*(r) #define S(r) PI*(r)*(r) void main() { float radius,circle,area; scanf("%f",&radius); circle=L(radius); area=S(radius); printf("radius:%f\tcircle:%f\tarea:%f\n", radiu

c语言中可变长度参数使用的注意事项

C语言中可变长度参数极大地方便了我们编程的同时,也非常容易由于使用不慎导致及其隐蔽的错误.以下面的这段函数为例,运行一段时间后会随机出现段错误,而且出错的位置一直稳定在vsprintf()函数里面. -----... a_list ap; va_start(ap, cmd); -----... rep = (redisReply *)redisvCommand(rc, cmd, ap); vsprintf(str, cmd, ap); -----... va_end(ap); 为了深入探究原因,

Struts2中带参数的结果集

1.在Struts2中带参数的结果集,即向结果集传参.struts2中有转发和重定向到某个视图,其中转发的过程在服务端完成,这个过程共享一个value stack(值栈),客户端并不知道页面跳转到了哪个jsp页面,其地址栏中显示的是所请求的action地址:在这个转发的过程中,参数值是共享的.其中重定向的话,服务器收到请求后,发现需要重定向,然后把需要重新访问的请求地址发给客户端,客户端重新发起请求,这个过程中,客户端知道自己访问的jsp页面的具体地址,其地址栏显示的是jsp页面的实际地址,并且