C——宏 VS 函数

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

内容简介: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。


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

查看所有标签

猜你喜欢:

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

计算机科学导论

计算机科学导论

Behrouz A.Forouzan / 刘艺 / 机械工业出版社 / 2009-1 / 30.00元

本书是大学计算机相关专业的基础课教材,涉及到计算机科学的各个方面。本书着重讲解基本概念而不是数学模型和技术细节,通过大量的图表和演示范例讲解计算机科学的基础知识;每章后面的关键术语、小结和练习有助于读者掌握和复习知识要点。 本书既适合当作大专院校的计算机基础课教材,也可作为一般的计算机基础入门读物。一起来看看 《计算机科学导论》 这本书的介绍吧!

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

随机密码生成器
随机密码生成器

多种字符组合密码

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试