C——宏 VS 函数

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

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


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

查看所有标签

猜你喜欢:

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

JavaScript & jQuery交互式Web前端开发

JavaScript & jQuery交互式Web前端开发

[美]达克特(Duckett,J.) / 杜伟、柴晓伟、涂曙光 / 清华大学出版社 / 2015-6-9 / 79.80元

欢迎选择一种更高效的学习JavaScript和jQuery的方式。 你是一名JavaScript新手?或是您曾经向自己的Web页面上添加过一些脚本,但想以一种更好的方式来实现它们?本书非常适合您。本书不仅向您展示如何阅读和编写JavaScript代码,同时还会以一种简单且视觉化的方式,教您有关计算机编程的基础知识。阅读本书之前,您只需要对HTML和CSS有一些了解即可。 通过将编程理论......一起来看看 《JavaScript & jQuery交互式Web前端开发》 这本书的介绍吧!

JS 压缩/解压工具
JS 压缩/解压工具

在线压缩/解压 JS 代码

URL 编码/解码
URL 编码/解码

URL 编码/解码

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具