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。


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

查看所有标签

猜你喜欢:

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

Web Development Recipes

Web Development Recipes

Brian P. Hogan、Chris Warren、Mike Weber、Chris Johnson、Aaron Godin / Pragmatic Bookshelf / 2012-1-22 / USD 35.00

You'll see a full spectrum of cutting-edge web development techniques, from UI and eye candy recipes to solutions for data analysis, testing, and web hosting. Make buttons and content stand out with s......一起来看看 《Web Development Recipes》 这本书的介绍吧!

CSS 压缩/解压工具
CSS 压缩/解压工具

在线压缩/解压 CSS 代码

Base64 编码/解码
Base64 编码/解码

Base64 编码/解码

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具