所谓的宏就是一种预处理命令,什么是与处理呢?即在编译过程之前先对程序代码做出的必要的转换处理。宏有两个作用:

1.当遇到需要将程序某个特定的数量在程序中出现的所有实例通通加以修改时,程序只需改动一处即可。

2.大多数C语言函数调用时都会带来重大的系统开销,而宏看上去像一个函数却没有函数调用的开销。

宏虽然有优点,但是也有其自身的缺陷。

首先得明确宏只是简单地替换。例如

#define CHAR char*

Int main()

{

Char a=’A’;

CHAR  p1,p2;

P1=&a;

P2=&a;//错误

}

在运行如上程序代码的时候程序会报错,什么原因呢?由于宏只是简单地替换,所以CHAR p1,p2;代表的是char *p1,p2;只有p1被定义成了指针,而p2只是字符类型的普通变量。

这样的简单替换往往会导致另一种错误出现:

#define add(a,b)   a + b

result = add (1,2) * add(3,4);

如上的定义的本意是先计算1与2,3与4之和,然后把他们的结果乘起来。但是运行的结果却不是我们想象的那样,编译器会把表达式简单替换为:1+2*3+4,这样我们就可以看出问题的所在了。要解决这种问题的出现,就是不要吝啬括号的使用。应针对每个宏参数和整个表达式都加上括号,避免歧义的产生。

其次,不能忽略宏定义中的空格。例如:

#define  f  (x)  ((x) * 2)

这种定义有两种可能的解释方式:

① 定义了宏 f, 其中f代表(x)  ((x) * 2)

② 定义了宏 f  (x),其中x是宏参数,f  (x)宏整体代表((x) * 2)

这两种定义只能是第一种,因为在宏定义时中间不能有空格。有了空格首先会对宏的理解产生歧义性,其次在编译时会产生意想不到的结果。因此应该避免这种情况的发生。

以上的规则只适用于宏的定义,在宏调用的时候中间有没有空格都无所谓。即f(5)与

f  (5)都是一样的。

最后,我们要关注的是宏的副作用。

宏看起来像函数,但它并不是函数。我们先看如下的代码:

#include<stdio.h>

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

int main()

{

char ar[3] = { 2, 3, 1 };

int i = 1; int biggest = ar[0];

while (i < 3)

{

biggest = max(biggest, ar[i++]);

}

printf("max value=%d\n", biggest);

return 0;

}

这段代码的本意是求出数组中最大的值,但是经过运行我们发现,运行的结果并不是我们所想象的3,而是1,这个结果明显错误,但是错在哪呢?我们先将上述的式子中的max进行宏替换:

biggest=biggest>ar[i++]?biggest:ar[i++];

首先,变量biggest与ar[i++]进行比较,此时i的值为1,ar[1]的值为3,而此时biggest的值为ar[0]为2,因此表达式的值为假。这里由于i++的副作用,比较后i递增为2.

因为关系运算的结果为假,所以ar[i++]的值被赋给biggest,然而此时i的值为2.所以实际赋给变量的值是ar[2]即1,这时,又因为i++的副作用,i的值变成3.因此也就不难理解为什么程序运行结果不是3而是1了。

要避免宏的副作用,这里有两个方法:

1.把i++提出来,即将原来的biggest=max(biggest,ar[i++]);

改为:biggest=max(biggest,ar[i]);

i++;

2.将宏改为函数

C语言之宏的更多相关文章

  1. C语言中宏定义(#define)时do{}while(0)的价值(转)

    C语言中宏定义(#define)时do{}while(0)的价值 最近在新公司的代码中发现到处用到do{...}while(0),google了一下,发现Stack Overflow上早有很多讨论,总 ...

  2. c 语言中宏定义和定义全局变量的区别

    宏定义和定义全局变量的区别: 1 作用时间不同. 宏定义在编译期间即会使用并替换,而全局变量要到运行时才可以. 2 本质类型不同. 宏定义的只是一段字符,在编译的时候被替换到引用的位置.在运行中是没有 ...

  3. 注解是建立在class文件基础上的东西,同C语言的宏有异曲同工的效果

    注解是建立在class文件基础上的东西,同C语言的宏有异曲同工的效果 https://www.cnblogs.com/deman/p/5519901.html @是java注解,即annotation ...

  4. C语言的宏macro的使用

    C's Macro Introduction 1.The Connect Macros: ## 这是一个预处理连接符,这个操作符主要用来将两个符号连接成为一个完整的宏符号.通过下面的代码,可以看到其具 ...

  5. C语言基础--宏

    宏在C语言中经常使用,在linux的源码中可以看到很多宏的高级应用.因此不理解宏,就很难理解代码.本文参考一些互联网资料做一些总结,希望给大家带来帮助. 先说说使用宏的优点及缺点: 优点: 1.提高代 ...

  6. 【编程基础】C语言常见宏定义

    我们在使用C语言编写程序的时候,常常会使用到宏定义以及宏编译指令,有的可能比较常用,有的可能并不是很常用,是不是所有的C语言宏定义以及宏指令你都清楚呢? 指令 用途详细介绍 # 空指令,无任何效果 # ...

  7. C语言在宏定义中使用语句表达式和预处理器运算符

    语句表达式的亮点在于定义复杂功能的宏.使用语句表达式来定义宏,不仅可以实现复杂的功能,而且还能避免宏定义带来的歧义和漏洞.下面以一个简单的最小值的宏为例子一步步说明. 1.灰常简单的么,使用条件运算符 ...

  8. C语言程序设计--宏和预处理

    C语言宏 宏定义常量 #include <stdio.h> #define SIZE 100 #define BANNER "WARNING:" int main(vo ...

  9. C语言高级宏技巧

    特殊符号#.## (1)# When you put a # before an argument in a preprocessor  macro, the preprocessor turns t ...

随机推荐

  1. 旨在脱离后端环境的前端开发套件 - IDT之Server篇

    IDT,一个基于Nodejs的,旨在脱离后端环境的前端开发套件,目的就是能让前端开发完全脱离后端的环境,无论后端是什么模板引擎(主流),都能应付自如. IDT主要包括两大部分:Server + Bui ...

  2. 分布式数据存储 - MySQL主从复制高可用方案

    前面几篇文章说道MySQL数据库的高可用方案主从复制.主从复制的延迟产生原因.延迟检测及延迟解决方案(并未从根本上解决),这种主从复制方案保证数据的冗余的同时可以做读写分离来分担系统压力但是并非是高可 ...

  3. 同一网站不同和二级域名和不同子目录的cookie

    1.cookie二级域名的实现: 用户其中一个站点登录,而且可以各个子频道间切换,保持登录状态设置Cookie时,使用如下代码即可:setcookie(name,value,expire,path,& ...

  4. Windows服务创建及安装

    Windows服务创建及安装http://www.cnblogs.com/tuyile006/archive/2006/11/27/573654.html

  5. URAL 1167. Bicolored Horses (DP)

    题目链接 题意 :农夫每天都会放马出去,然后晚上把马赶入马厩,于是让马排成一行入马厩,但是不想马走更多的路,所以让前p1匹入第一个马厩,p2匹马入第二个马厩…………但是他不想让他的任何一个马厩空着,所 ...

  6. DB2对年份的处理Year()

    public DataSet GetCustomerAllocListByQC(CustomerAllocQueryDataContract aQC) { StringBuilder sql = ne ...

  7. UVA 10892 LCM Cardinality 数学

    A pair of numbers has a unique LCM but a single number can be the LCM of more than one possiblepairs ...

  8. 浅谈Spark Kryo serialization

    原创文章,转载请注明: 转载自http://www.cnblogs.com/tovin/p/3833985.html 最近在使用spark开发过程中发现当数据量很大时,如果cache数据将消耗很多的内 ...

  9. redis资料汇总

    redis资源比较零散,引用nosqlfan上的文章,方便大家需要时翻阅.大家看完所有的,如果整理出文章的,麻烦知会一下,方便学习. 1.Redis是什么? 十五分钟介绍 Redis数据结构 Redi ...

  10. Eclipse中WEB项目自动部署到Tomcat

    原因 很长时间没用Eclipse了,近期由于又要用它做个简单的JSP项目,又要重新学习了,虽然熟悉的很快,但记忆总是很模糊,偶尔犯错,以前很少写博客,现在感觉还是很有必要的,编程中每个人对于犯过的错误 ...