关于宏的认识

        百度百科是这么来定义宏的:宏是一种批量批处理的称谓。一般说来,宏是一种规则或模式,或称语法替换,用于说明某一特定输入(通常是字符串)如何根据预定义的规则转化成对应的输出(通常也是字符串)。这种替换在预编译时进行。
    这里先脑补一下高级语言的编译过程:码农辛苦敲进去的叫源程序(.cpp),第一步是预处理,第二步是编译,第三步是汇编,第四步是链接。

          
C语言编译过程

   一, 预处理:编译前做的准备。主要有四个作用:宏替换,头文件展开,去注释,条件编译。宏替换时时需要涉及以下三个步骤:

               1,首先对参数进行检查,凡是包含了任何由#define定义的符号都首先被替换;

               2,替换文本随后被插入到程序中原来文本的位置;

               3,再次对结果文本进行扫描,看它是否包含了任何由#define定义的符号,如果是,就重复上述过程。

           下面表格罗列了由预处理器定义的符号,他们的值或者是字符串常量,或者是十进制数字常量。__FILE__和__LINE__在确认调试输出的来源方面很有用处。                           __DATE__   和__TIME__常常用在被编译的程序中加入版本信息。__STDC__用在那些在ANSI环境和非ANSI环境都必须进行编译的程序中结合条件编译。

             这里有#和##结构的用法注意留意:使用预处理器把一个宏参数转变为一个字符串。#argument这种结构被预处理器翻译                 为“argument”。看下面例子:
                 #define PRINT(FORMAT,VALUE) \
                                printf("the value of "#VALUE\
                               "is"FORMAT"\n",VALUE)
                  ...
                   PRINT("%d",x+3);
                  它将输出:the value of x+3 is 25
            ##结构把位于他两边的符号连接为一个符号。作为用途之一,他允许宏定义从分离的文本片段创建标识符。看下面例子
                   #define ADD_TO_SUM(sum_number,value)   sum ## sujm_number +=value
                       ...
                  ADD_TO_SUM(5,25);
               最后一条语句将值加到变量sum5.注意这种连接必须产生一个合法的标识符。否则,其结果就是未定义的。
  二,编译:   经过编译生成汇编语言,得到汇编文件(.s)
  三,汇编:  经过汇编生成目标二进制文件(.obj)
  四,链接: 分为动态链接和静态链接。生成可执行程序(.exe)。静态链接方法:#pragma comment(lib, "test.lib") ,静态链接的时候,载入代码就会把程序会用到的动态代码或动态代码的地址确定下来静态库的链接可以使用静态链接,动态链接库也可以使用这种方法链接导入库。而动态链接方法:LoadLibrary()/GetProcessAddress()和FreeLibrary(),使用这种方式的程序并不在一开始就完成动态链接,而是直到真正调用动态库代码时,载入程序才计算(被调用的那部分)动态代码的逻辑地址,然后等到某个时候,程序又需要调用另外某块动态代码时,载入程序又去计算这部分代码的逻辑地址,所以,这种方式使程序初始化时间较短,但运行期间的性能比不上静态链接的程序。
   

 接下来我们来看看宏这一概念
       #define PI 3.1415926 这就是一个宏定义,在此后的代码中你尽可能使用PI来替代3.1415926,这样一是输入简单且保证高的输入正确率,而且在以后需要修改的话,只需要修改一次PI就ok了。
        除了定义常数以外,经常还用来定义字符串,尤其是路径:
             #define ENG_PATH_  E:\English\listen_to_this\listen\
             _to_this_3
        这里应该注意一下接续符反斜杠,反斜杠作为接续符时,在本行其后面不能再有任何字符,空格也不行。所以上述例子只有第一行最后一个反斜杠是接续符。
       还有定义表达式。(这里往往就是雷区,在这得多注意)
          #define SQR(x) x*x
        如果x这个表达式是1+5,请问最后结果是多少?大意的同学可能就掉坑了,认为答案是6*6=36,实际上应该是1+5*1+5=11。所以这里就应该注意:给每一个参数都带上小括号,整体也带上小括号,避免运算符的优先级引起不必要的错误。
注意七点 :1,函数宏被调用时是以实参代替形参,而不是“值传送”。
                   2,宏语句体外的末尾必须省略分号。
                   3,注意宏定义中的空格。 比如 #define SUM (x) ((x)+(x)) 这定义的还是SUM(x)?显然不是的,编译器会认为这是定义了宏SUM,其代表的是(x) ((x)+(x))
                   4,宏名称是个整体,中间不能出现空格。
                   5,#undef 是用来撤销宏定义的。他的前面肯定与之对应有#define。#undef此后的代码就不能用对应的宏了。  
                   6,宏不能用于递归。
                   7,遵守命名规则(宏名称大写),增加代码的可读性。

函数与宏
         宏非常频繁地执行简单的计算,比如求最大值:#define MAX(a,b)  ((a)>(b)?(a):(b)) 这个任务函数也可以进行,但是没使用函数,这有两个原因:首先,用于调用和从函数返回的代码很可能比实际执行这个小型计算工作的代码更大,所以使用宏比使用函数在程序的规模和速度方面都更胜一筹。但更为重要的是函数的参数必须声明一种特定的类型,而宏与类型无关。
        但是宏也是有缺点的,主要有四点:

                                     1,使代码显得臃肿;
                                     2,因为与类型无关,所以编译出现的与类型有关的问题就不会提醒,会为以后埋下隐患;
                                     3,写起来比函数更难;
                                     4,可能产生副作用。具有副作用的参数可能在宏的使用过程中产生意想不到的结果。

看下图,函数和宏的区别


     以上是我对宏的一些浅显认识,请读者多指教。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值