zoukankan      html  css  js  c++  java
  • const与#define宏常量 , inline与#define

    1.预处理

      预处理器是在真正的编译开始之前由编译器调用的独立程序。预处理器可以删除注释、包含其他文件以及执行宏替代。

         预处理命令(宏定义#define..#undef、

                          文件包含#include、

                         条件编译#ifndef...(#else)...#endif   或者   #if...(#else)..#endif)

          不是C++语句(以“#”开头,末尾不包含分号),不能直接编译。

        宏的优缺点说明:

        1). 首先谈一下在C中使用这种形式宏定义的原因,C语言是一个效率很高的语言,这种宏定义在形式及使用上像一个函

                数,但它使用预处理器实现,没有参数压栈,代码生成等一系列的操作,因此,效率很高,这是它在C中被使用的一个

                主要原因。

         2). 这种宏定义在形式上类似于一个函数,但在使用它时,仅仅只是做预处理器符号表中简单替换,因此它不能进行

                 参数有效性的检测也就不能享受C++编译器严格类型检查的好处,另外它的返回值也不能被强制转换为可转换的合适的

                  类型,这样,它的使用就存在着一系列的隐患和局限性

         3). 在C++中引入了类及类的访问控制,这样,如果一个操作或者说一个表达式涉及到类的保护成员或私有成员,就不

                 可能使用这种宏定义来实现(因为无法将this指针放在合适的位置)。

    2. inline

         inline 推出的目的:为了取代宏定义,它消除了宏定义的缺点,同时又很好地继承了宏定义的优点。

         inline的优点

         1). inline 定义的类的内联函数,函数的代码被放入符号表中,在使用时直接进行替换,(像宏一样展开),没有了调用的开销,效率很高。

         2). 类的内联函数也是一个真正的函数,编译器在调用一个内联函数时,会首先检查它的参数的类型,保证调用正确。然后进行一系列的相关检查,

                就像对待任何一个真正的函数一样。这样就消除了它的隐患和局限性

         3). inline 可以作为某个类的成员函数,当然就可以在其中使用所在类的保护成员及私有成员

         注意:可以在声明函数和定义函数的时候同时写inline,也可以只在其中一处声明inline,效果相同,都能按内置函数处理。

        inline的局限性

          1). 使用内置函数可以节省运行时间,但却增加了目标程序的长度。因此一般只将规模很小而使用频繁的函数声明为内置函数

          2). 内置函数不包含复杂的控制语句,如循环语句和switch语句

          3). 对函数inline声明,只是程序设计者对编译系统提出的一个建议,编译系统会根据具体情况决定是否这样做。

         慎用内联:

           内联是以代码膨胀(复制)为代价,仅仅省去了函数调用的开销,从而提高函数的执行效率。如果执行函数体内代码的时间,相比于函数调用的开销较大,那么效率的收获会很少。另一方面,每一处内联函数的调用都要复制代码,将使程序的总代码量增大,消耗更多的内存空间。

        以下情况不宜使用内联:         

        (1)如果函数体内的代码比较长,使用内联将导致内存消耗代价较高。    

        (2)如果函数体内出现循环,那么执行函数体内代码的时间要比函数调用的开销大。       

        (3)类的构造函数和析构函数容易让人误解成使用内联更有效。要当心构造函数和析构函数可能会隐藏一些

               行为,如“偷偷地”执行了基类或成员对象的构造函数和析构函数。所以不要随便地将构造函数和析构函数的定义体放在类声明中。

          inline与宏的区别总结:

           1). 内联函数和宏的区别在于,是由预处理器对宏进行替代,而内联函数是通过编译器控制来实现的。而且内联函数是真正的函数,

              只是在需要用到的时候,内联函数像宏一样的展开,所以取消了函数的参数压栈,减少了调用的开销。

           2). 内联函数与带参数宏定义的另一个区别是,内联函数的参数类型返回值类型在声明中都有明确的指定;而带参数宏

               定义的参数没有类型的概念,只有在宏展开以后,才由编译器检查语法,这就存在很多的安全隐患。

    3. const 推出的初始目的:为了取代预编译指令,消除它的缺点,同时继承它的优点。

         const的作用

         (1)便于进行类型检查,使编译器对处理内容有更多了解,消除了一些隐患。可以保护被修饰的东西,防止意外的修改,增强程序的健壮性
       (2)可以避免意义模糊的数字出现,同样可以很方便地进行参数的调整和修改同宏定义一样,可以做到不变则已,一变都变
       (3) 可以节省空间,避免不必要的内存分配。 例如: 
        #define PA 3.14159 //常量宏 
        const double Pi=3.14159; //此时并未将Pi放入RAM中 ...... 
        double i=Pi; //此时为Pi分配内存,以后不再分配 
        double I=PA; //编译期间进行宏替换,分配内存 
        double j=Pi; //没有内存分配 
        double J=PA; //再进行宏替换,又一次分配内存! 
            const定义常量从汇编的角度来看,只是给出了对应的内存地址,而不是象#define一样给出的是立即数,

                 所以,const定义的常量在程序运行过程中只有一份拷贝,而#define定义的常量在内存中有若干个拷贝 
      (4) 提高了效率。 
            编译器通常不为普通const常量分配存储空间,而是将它们保存在符号表中,这使得它成为一个编译期间的常量没有了存储与读内存的操作,使得它的效率也很高

        const与宏常量的区别:

           1). const常量有数据类型,而宏常量没有数据类型 编译器可以对前者进行类型安全检查,而对后者只能进行字符替换,没有安全检查,

               并且在字符替换时可能会产生意料不到的错误。

           2). 编译器对二者的调试 有些集成化的调试工具可以对const常量进行调试, 在 c++程序中只使用const常量而不使用宏常量,

                 即const常量完全取代宏常量。

    通过上面的分析,总结为一句话:尽量用编译器(const、inline),而不用预处理(#define)。

  • 相关阅读:
    字符串的问题(strstr和strncpy 水题)
    数一数(KMP+思维)
    栗酱的数列(KMP+思维)
    D. Almost All Divisors(思维)
    E. Two Arrays and Sum of Functions(贪心)
    好位置(思维)
    Just A String(kmp)
    Dubbo简介
    lambda表达式快速创建
    分布式RPC系统框架Dubbo
  • 原文地址:https://www.cnblogs.com/Xylophone/p/3633758.html
Copyright © 2011-2022 走看看