重庆分公司,新征程启航
为企业提供网站建设、域名注册、服务器等服务
#define M(a) a*a
专注于为中小企业提供成都网站建设、做网站服务,电脑端+手机端+微信端的三站合一,更高效的管理,为中小企业会昌免费做网站提供优质的服务。我们立足成都,凝聚了一批互联网行业人才,有力地推动了超过千家企业的稳健成长,帮助中小企业通过网站建设实现规模扩充和转变。
宏里面描述的a相当于函数的参数,它和你描述的主函数的a是没关系的,预处理时对宏只是做简单的替换。。例如
#include "stdio.h"
#define M(a) a*a
int main()
{
int i = 10;
printf("%d\n",M(i));
return 0;
}
这里会把M(i)替换成 i*i。。。。
宏定义是C提供的三种预处理功能的其中一种,这三种预处理包括:宏定义、文件包含、条件编译
宏定义又称为宏代换、宏替换,简称“宏”。
格式:
#define 标识符 字符串
其中的标识符就是所谓的符号常量,也称为“宏名”。
预处理(预编译)工作也叫做宏展开:将宏名替换为字符串。
掌握"宏"概念的关键是“换”。一切以换为前提、做任何事情之前先要换,准确理解之前就要“换”。
即在对相关命令或语句的含义和功能作具体分析之前就要换:
例:
#define PI 3.1415926
把程序中出现的PI全部换成3.1415926
说明:
(1)宏名一般用大写
(2)使用宏可提高程序的通用性和易读性,减少不一致性,减少输入错误和便于修改。例如:数组大小常用宏定义
(3)预处理是在编译之前的处理,而编译工作的任务之一就是语法检查,预处理不做语法检查。
(4)宏定义末尾不加分号;
(5)宏定义写在函数的花括号外边,作用域为其后的程序,通常在文件的最开头。
(6)可以用#undef命令终止宏定义的作用域
(7)宏定义不可以嵌套
(8)字符串" "中永远不包含宏
(9)宏定义不分配内存,变量定义分配内存。
(10)宏定义不存在类型问题,它的参数也是无类型的。
这样可以么?
C语言中的宏定义用法分为两种。
1、不带参数的宏定义比较简单,就是用一个指定的标识符来代表一个字符串。它的一般形式为“#define 标识符 字符串”,例如#define E 2.718281828459。这种方法使用户能以一个简单的名字代替一个长的字符串。
2、带参数的宏定义不是仅仅进行简单的字符串替换,还要进行参数替换。其定义的一般形式为;“#define 标识符(宏名)(参数表) 字符串”,字符串中包含在括号中所指定的参数。例如#define S(a,b) a*b area=S(3. 2)。
扩展资料:
宏定义只占编译时间,函数调用则占用运行时间(分配单元,保存现场,值传递,返回),每次执行都要载入,所以执行相对宏定义会较慢。
使用宏定义次数多时,宏定义展开后源程序很长,因为每展开一次都使程序增长,但是执行起来比较快一点(这也不是绝对的,当有很多宏定义展开,目标文件很大,执行的时候运行时系统换页频繁,效率就会低下)。而函数调用不使源程序变长。
宏定义的基础知识。引用宏定义时,直接代入进行代换。
既然已经宏定义SUB(a) (a)-(a),而程序中出现的对应a的是a+b,那么就将a换为a+b代入表达式:
d=SUB(a+b)*c=(a+b)-(a+b)*c=(2+3)-(2+3)*5
直接用(a+b)-(a+b)代换SUB(a+b)。这一点和数学是不同的,不要强行往数学上靠。
主要用于函数重定义,通用性,可以用一个变量符号替代另一个变量符号
格式:#define M(x,y) x+y
在主程序里写入z=M(6,9);等价于z=6+9;而写成z=(6-8,9);等价于z=6-8+9 ;直接代入
还有就是 :#define Uint unsigned int 即用 Uint 代替unsigned int 便于书写,还有就是不同操作系统的通用变量识别
我们以下面两行代码为例,展开描述:
函数式宏定义:#define MAX(a,b) ((a)(b)?(a):(b))
普通函数 :MAX(a,b) { return ab?a:b;}
(1)函数式宏定义的参数没有类型,预处理器只负责做形式上的替换,而不做参数类型检查,所以传参时要格外小心。
(2)调用真正函数的代码和调用函数式宏定义的代码编译生成的指令不同。
如果MAX是个普通函数,那么它的函数体return a b ? a : b; 要编译生成指令,代码中出现的每次调用也要编译生成传参指令和call指令。而如果MAX是个函数式宏定义,这个宏定义本身倒不必编译生成指令,但是代码中出现的每次调用编译生成的指令都相当于一个函数体,而不是简单的几条传参指令和call指令。所以,使用函数式宏定义编译生成的目标文件会比较大。
(3)函数式宏定义要注意格式,尤其是括号。
如果上面的函数式宏定义写成 #define MAX(a, b) (ab?a:b),省去内层括号,则宏展开就成了k = (i0x0fj0x0f?i0x0f:j0x0f),运算的优先级就错了。同样道理,这个宏定义的外层括号也是不能省的。若函数中是宏替换为 ++MAX(a,b),则宏展开就成了 ++(a)(b)?(a):(b),运算优先级也是错了。
(4)若函数参数为表达式,则普通函数的调用与函数式宏定义的替换过程是不一样的。
普通函数调用时先求实参表达式的值再传给形参,如果实参表达式有Side Effect,那么这些SideEffect只发生一次。例如MAX(++a, ++b),如果MAX是普通函数,a和b只增加一次。但如果MAX函数式宏定义,则要展开成k = ((++a)(++b)?(++a):(++b)),a和b就不一定是增加一次还是两次了。所以若参数是表达式,替换函数式宏定义时一定要仔细看好。
5)函数式宏定义往往会导致较低的代码执行效率。
看下面一段代码:
复制代码代码如下:
int a[]={9,3,5,2,1,0,8,7,6,4};
int max(n)
{
return n==0?a[0]:MAX(a[n],max(n-1));
}
int main()
{
max(9);
return 0;
}
若是普通函数,则通过递归,可取的最大值,时间复杂度为O(n)。但若是函数式宏定义,则宏展开为( a[n]max(n-1)?a[n]:max(n-1) ),其中max(n-1)被调用了两遍,这样依此递归下去,时间复杂度会很高。
尽管函数式宏定义和普通函数相比有很多缺点,但只要小心使用还是会显著提高代码的执行效率,毕竟省去了分配和释放栈帧、传参、传返回值等一系列工作,因此那些简短并且被频繁调用的函数经常用函数式宏定义来代替实现。