C——宏 VS 函数

栏目: 编程语言 · 发布时间: 8年前

内容简介:C——宏 VS 函数

想要了解宏和函数,就得先介绍下一个.c代码是如何到最后的可执行文件的,主要经过了以下几个阶段:

C——宏 VS 函数

①预处理器处理过程中又可以分为:1>删除注释;2>头文件展开(将所包含的头文件内容全部复制到此文件中);3>宏替换;4>条件编译

②编译过程可以分为: 1>词法分析;2>语义分析;3>符号汇总;4>语法分析

③汇编过程则是将形成的汇编代码转换成二进制代码,同时形成对应的符号表。

先分别简单介绍下函数和宏:

①#define宏:把参数替换到文本中,通常称为宏或者定义宏;

②函数:它负责完成某项特定任务,而且相较于其他代码,具备相对的独立性。每次使用时只需要调用即可。

接下来总结下宏和函数各自在不同分析角度下的情况:

1>代码长度:

#define宏:使用了几次宏,相对应的宏代码就会被插入到代码中几次,所以如果你的宏不是很小,并且使用次数也不少,那么整体的代码长度就会大幅增加;

函数:函数代码只需要写一份,代码在执行时每次遇到函数调用那么就去函数内部执行一次,并不会大幅增加代码程度、

2>执行速度:

#define宏:由于在代码 在预编译时就已经将参数替换了进去,执行速度很快;

函数:函数涉及到传参问题以及调用函数并返回的过程,会增加执行时间

3>操作符优先级:

#define宏: 这就是一个大坑,千万不要想着省你的括号!!! 稍后看例1就会知道了。如果你的括号不够多,那么很可能会出现你意料之外的运行结果;

函数:表达式的求值结果更容易预测。

4>参数求值:

#define宏 :参数每次用于宏定义时,都会被重新求值,所以具有副作用的参数就又会产生你意料不到的结果, 这也是一个坑!!!! 一会看例2就知道了;

函数:参数在调用前只求值一次,不会导致多种求值问题,参数副作用也不会造成任何问题。

5>参数类型

#define宏:宏与类型无关,只要参数操作合法,便可以适用于任何参数类型;

函数:函数在传参时就规定了类型,不能随意使用。

现在就到了跳坑的时候(如果你基础不是很好,那么你一定会掉进去):

例1:

#define _CRT_SECURE_NO_WARNINGS 1
#define  SQUARE(X) X * X

#include <stdio.h>
#include <Windows.h>

int main()
{
	int x = 5;
	printf("%d\n", SQUARE(x+1));
	printf("%d\n", 10 * SQUARE(x+1));
	system("pause");
	return 0;
}

可以先自己按照自己的理解推断下输出结果:

先来分析第一个printf:如果你认为会打印出的结果是36那恭喜你成功的掉坑里了。宏是把参数替换到文本中!一定要注意是替换!!所以该语句可以等价为

printf("%d\n", x + 1 * x + 1);      这样一看结果很显而易见是11

如果你想输出6 *6 那就需要将宏改为(X)*(X),这样经过预处理之后就等价于

printf("%d\n",(x+1)*(x+1));        结果也就变成了6 * 6

经过了第一个printf,第二个如果你认为结果为10*5+1*5+1 = 56那就说明你理解了替换的意思了,否则还需要再练练。第一个坑到这就暂时告一段落

例2:

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

#include <stdio.h>
#include <Windows.h>

int main()
{
	int x = 5;
	int y = 8;
	int z = MAX(x++, y++);
	printf("x=%d, y=%d, z=%d", x, y, z);
	system("pause");
	return 0;
}

我们定义了一个宏用来求a,b两个参数中的较大值,这时候在参数替换后,整个z的赋值语句等价于:

int z = (  (x++) > (y++) ) ? (x++) : (y++) );

所以在进行比较时是用的++前的值,也就是5和8进行比,在判断完这个的同时,5和8同时完成后增操作变成6和9,三目运算符如果条件成立则运算冒号前的表达式,冒号后的表达式不运算,显然此次判断运算y++,y就变成了10;

最后的printf打印出:x=6, y=10, z=9;这个时候就出现了我们所谓的副作用,我们并不想将y自增两次。

但是用函数就可以完成我们想要完成的事情:

#define _CRT_SECURE_NO_WARNINGS 1

#include <stdio.h>
#include <Windows.h>

int Max(int x, int y)
{
	return x > y ? x: y;
}

int main()
{
	int x = 5;
	int y = 8;
	int z = Max(x++, y++);
	printf("x=%d, y=%d, z=%d", x, y, z); // x=6,y=9,z=8
	system("pause");
	return 0;
}

主要区别就在于我们上面所提到的参数在函数被调用前只求值一次,在函数中多次使用参数并不会导致多种求值过程,而#define宏定义则会在某些情况下产生意想不到的副作用。所以我们在一般使用函数或宏定义实现某个功能时,可以在不同的情况下考虑用不同的方法,前提是一定要有能掌握它的能力,否则到时候又会让你多出一些BUG。


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

重来

重来

[美] 贾森·弗里德、[丹] 戴维·海涅迈尔·汉森 / 李瑜偲 / 中信出版社 / 2010-10 / 36.00元

大多数的企业管理的书籍都会告诉你:制定商业计划、分析竞争形势、寻找投资人等等。如果你要找的是那样的书,那么把这本书放回书架吧。 这本书呈现的是一种更好、更简单的经商成功之道。读完这本书,你就会明白为什么计划实际上百害而无一益,为什么你不需要外界投资人,为什么将竞争视而不见反倒会发展得更好。事实是你所需要的比你想象的少得多。你不必成为工作狂,你不必大量招兵买马,你不必把时间浪费在案头工作和会议......一起来看看 《重来》 这本书的介绍吧!

HTML 压缩/解压工具
HTML 压缩/解压工具

在线压缩/解压 HTML 代码

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

RGB转16进制工具
RGB转16进制工具

RGB HEX 互转工具