宏, const变量, 内联, 枚举

  宏

    宏定义:  宏即宏替换,在C语言源程序中允许用一个标识符来表示一个字符串,称为宏,关键字 define,在所有使用到宏的地方都只是直接的替换而不做任何类型检查

      宏替换是C提供的三种预处理功能的其中一种,这三种预处理包括:宏定义,文件包含,条件编译,C++继承C的遗产,在C++中也可以使用宏,宏不能访问对象的私有成员,

      宏的定义很容易产生二义性    

    特点:在预处理阶段对宏定义的替换,使用时要特别小心;宏本身不占用内存单元,但每次调用都分配内存;语句的最后不加分号;无数据类型;非常量,只是盲目替换;是全局的

    使用:(1) 防止头文件被重复包含

        #ifndef COMDEF_H    //#:字符串化运算符,在一个预处理器宏中的参数前面使用#,预处理器会把这个参数转换为一个字符数组,并把这一点与没有插入标点符号的若干个

        #define COMDEF_H    //字符数结合而链接成一个单独的字符数组,能够生成一个十分方便的宏用于调试期间打印出变量的值

        ......            //中间可以有任意个空格,串一但开始,仅由一新行结束,宏名定以后,即可成为其他宏名定义中的一部分;

        #endif           //宏替换仅仅是以文本串代替宏标识符,前提是宏标识符必须独立的识别出来,否则不进行替换,如果串长于一行,可以在该行末尾用反斜杠'\'续行

       (2) 重新定义一些类型,防止由于各种平台和编译器的不同,而产生的类型字节数差异,方便移植

        typedef unsigned char boolean;   /*Boolean value type */

        typedef unsigned long int uint32;    /*Unsigned 32 bit value */

        typedef signed char int8;      /*Signed 8 bit value */

        typedef signed long int int32     /*Signed 32 bit value */

       (3) 得到指定地址上的一个字节或字    //为防止出现包含错误,所有的参数都要用小括号包含

        #define MEM_B(x) (*((byte *)(x)))  //字节

        #define MEM_W(x) (*((word *)(x)))  //字

       (4) 求最大值和最小值

        #define MAX(x, y) ((x)>(y)?):(x):(y)  //最大值

        #define MIN(x, y) ((x)<(y)?):(x):(y)  //最小值

       (5) 判断字符是不是十进制的数字

        #define DECCHK(c)  ((c) >='0' && (c) <= '9')

       (6) 使用一些宏跟踪调试

        ANSI标准说明了五个预定义的宏名:__LINE__,__FILE__,__DATE__,__TIME__,__STDC__

        __LINE__:存放当前行号的整型字面值;

        __FILE__:存放文件名的字符串字面值;

        __DATE__:存放文件编译日期的字符串字面值

        __TIME__:存放编译时间的字符串字面值

        __STDC__:当要求程序严格遵循ANSI C标准时该标识被赋值为1;

        __FUNCTION__ 当前所在函数名

       (7) 关于#和##,#的功能是将其后面的宏参数进行字符串化操作,简单说就是对它所引用的宏变量通过替换后在其左右各加一个双引号

        ##被称为连接符,用来将两个Token连接为一个Token,它允许设两个标识符并把它们粘贴在一起自动产生一个新的标识符

        #define COMMAND(NAME) {#NAME,NAME##_command}

        例子:define FILED(a) char *a##_string; int a##_size

          class Record {

            FIELD(one);

            FIELD(two);

            FIELD(three);

            ...

           };

          每次调用FIELD()宏,将产生一个保存字符串数组的标识符和另一个保存字符数组长度的标识符,它不仅易读而且消除了编码出错,使维护更容易

       #define ChECK_NULLPTR_IQA(p)\   //: \必不可少,表示一句没写完,是用来续行的

        if (NULL == p) {\

        NGLogDebug("IQA", "%s Memory allocation failed!", __PRETTY_FUNCTION__);\

        return;\

        }\

        else {\

        NGLogDebug("IQA", "%s Memory allocation success ! p = %p", __PRETTY_FUNCTION__, p);\

        }

        实际调用中会出现下面所示的替换过程

        #define CHECK_NULLPTR_IQA(m_pFCSettingModel);

        if (NULL == m_pFCSettingModel) {

          NGLogDebug("IQA", "%s Memory allocation failed!", __PRETTY_FUNCTION__);

        }  

        else {

          NGLogDebug("IQA", "%s Memory allocation success ! m_pFCSettingModel = %p", __PRETTY_FUNCTION__, m_pFCSettingModel);\

        }        

  const 常量

    程序运行时在常量表中,系统为它分配内存,在堆栈分配了空间;const常量有数据类型;语句末有分号;有类型检查;可以限制范围 //将所有不希望改变的变量加const修饰

    const int a = 1;在类中定义并初始化const变量是不合法的

    static QString CC_VERTICAL_LINE("TEX_PNG_BUHIN_01_12");  //静态变量也是只能在类中定义不能初始化

    static const int a = 1;const static char *LogTag = "ScreenOff";   //只有静态const变量才可以在类中声明定义,非静态常量都只能在类中声明定义,在构造函数中初始化

    普通变量可以在类中声明与定义,在构造函数中进行初始化,静态成员是"类级别的",也就是它和类的地位相同,而普通成员是"对象级别(即类的实例化级别)".类级别的成员先于该类任何对象的存在而存在,

    它被该类所有对象共享,可以 推测一下:现在要实例化一个对象,那么静态变量是需要包含在这个对象里的对吧,假设是实例化对象的时候才定义这个变量,那么若是此时另一个线程也要创建这个类的对象,

    若假设成立,则产生问题:1. 静态变量的重复定义 2. 即使不产生重复定义,那么也会产生竞争,造成死锁,从而无法成功创建对象,所以:普通静态成员需要在类中声明与定义,在类外初始化

  内联

    定义:是用inline关键字修饰的函数,目的是为了消除函数调用时的时间开销,从源代码层看,有函数的结构,而在编译后,却不具备函数的性质,内联函数不是在调用时发生控制转移,

      而是在编译时将函数体嵌入在每个调用处

    特点:是在被调用的地方被展开而不生成执行代码

    优点:既保持预处理宏的效率又增加安全性,还能像一般成员函数一样可以在类里访问自如

    条件:1.递归函数不能定义为内联函数 2. 内联函数一般适合于不存在while和switch等复杂的结构且只有1~5条语句的小函数上,否则编译系统将该函数视为普通函数

       3. 内联函数只能先定义后使用,否则编译系统也会把它认为是普通函数 4. 对内联函数不能进行异常的接口声明 5. 定义了静态变量的函数不能成为内联函数

    inline:函数如果定义在类中,那么会自动被认为是申请成为内联函数,如果在类外,那么需要加关键字inline对编译器进行申请,在类外定义的函数如果不加inline关键字,那么一定不是内联函数,

      inline关键字是对编译器的一个申请,能不能成为内联函数,还要看编译器对该函数定义的具体处理;在类中定义的时候必须把函数体和声明结合在一起;主张所有的内联函数都定义在类外,

      用inline关键字声明,这样可以减少混乱。

    递归函数:如果一个函数调用了它自身,不管是直接的还是间接的,都称该函数为递归函数

      例如:求一个变量val的阶乘

        int factorial(int val) {

          if (val > 1) {    // 递归条件

            return factorial(val -1)*val;  //递归语句

           }

          else {

            return 1;  //递归结束条件

           }

  枚举

    定义:枚举是C++的一种派生数据类型,它是由用户定义的若干枚举常量的集合 

    特点:在编译的时候确定其值,可以一次定义大量相关的常量,枚举可以被限制名字空间,类内部,值会自动加1,如果没设初值,那么会从0开始,枚举有类型,因为其存储方式与int相似,所以枚举值可以

      当做int型使用,但使用时最好还是进行强制类型装换

    例子:两个不同类型的枚举值之间需要先进行类型转换,再进行比较

        enum Colors {Red, Green, Blue, Yellow}    //枚举值的定义最好使用十六进制,因为十六进制转换为二进制会更快

        (int)Colors.Red //枚举值转换为int  现在最好使用新式转换, int i = static_cast<int>(Color.Red)

        枚举值可以当做int型使用,如 enum {Number = 5;}  int scores[Number];

    

C++学习笔记 宏 const 内联 枚举的更多相关文章

  1. const 内联 枚举 宏

    const 常量   程序运行时在常量表中,系统为它分配内存,在堆栈分配了空间:const常量有数据类型:语句末有分号:有类型检查:可以限制范围 //将所有不希望改变的变量加const修饰 const ...

  2. c++学习笔记3(内联函数)

    函数调用是有开销的,调用时需将参数放入栈中,返回地址也要放入,返回时还需从栈中取出,跳转返回地址去执行,需几条语句的时间,如果本身程序代码短,则会显得十分浪费,所以引入了内联函数的机制 写法:在函数前 ...

  3. C/C++之宏、内联函数和普通函数的区别

    内联函数的执行过程与带参数宏定义很相似,但参数的处理不同.带参数的宏定义并不对参数进行运算,而是直接替换:内联函数首先是函数,这就意味着函数的很多性质都适用于内联函数,即内联函数先把参数表达式进行运算 ...

  4. c++ _宏与内联函数

    第一部分:宏为什么要使用宏呢?因为函数的调用必须要将程序执行的顺序转移到函数所存放在内存中的某个地址,将函数的程序内容执行完后,再返回到转去执行该函数前的地方.这种转移操作要求在转去执行前要保存现场并 ...

  5. C# step by step 学习笔记8 CHAPTER 9 使用枚举和结构创建值类型

    C# 2012 step by step 学习笔记8 CHAPTER 9 使用枚举和结构创建值类型 本章内容 声明一个枚举类型 创建并使用一个枚举类型 声明一个结构类型 创建并使用一个结构类型 解释结 ...

  6. C语言学习笔记10-结构体、枚举、联合体

    C语言学习笔记10-结构体.枚举.联合体    待传

  7. 宏 函数 内联函数inline

    带参宏有时候可以代替函数作用:优点直接替代,省去函数调用过程的开销:但缺点也是很明显:容易出错,系统不做检查非常容易出错. 改进方案:内联函数:既有带参宏的直接替代(拷贝)的优点,又有系统检查的优点. ...

  8. hive学习笔记之七:内置函数

    欢迎访问我的GitHub https://github.com/zq2599/blog_demos 内容:所有原创文章分类汇总及配套源码,涉及Java.Docker.Kubernetes.DevOPS ...

  9. Docker学习笔记 - Docker容器内部署redis

    Docker学习笔记(2-4)Docker应用实验-redist server 和client的安装使用 一.获取redis容器(含客户端和服务端) 二.创建服务端容器 1.在终端A中运行redis- ...

随机推荐

  1. Android-组件RadioButton使用技巧

    当初第一次接触Android组件的时候,我感觉微信底部的菜单,是用button这样的组件来做的. 可我想错了.却是用RadioButton来做的.那到底怎么做,接下来我就做一下分享!希望看了之后你也觉 ...

  2. python 线程之 threading(二)

    在http://www.cnblogs.com/someoneHan/p/6204640.html 线程一中对threading线程的开启调用做了简单的介绍 1 在线程开始之后,线程开始独立的运行直到 ...

  3. 首师大附中互测题:50229234海岛帝国:独立之战【C002】

    [C002]50229234海岛帝国:独立之战[难度C]———————————————————————————————————————————————————————————————————————— ...

  4. Android入门(七):Spinner下拉式菜单组件

    对于手机和平板电脑的应用程序来说,打字是非常不方便的操作方式,比较好的方式就是列出一组选项让用户挑选,这样就可以避免打字的麻烦.使用Spinner下拉菜单组件需要完成以下几个步骤: 1.建立选项列表, ...

  5. 在Oracle SQLplus下建用户 建表

    在建表之前最好新建一个用户,因为在sys用户下的表格不允许删除列, 所以最好不要在sys用户下建表. 一.在Oracle SQLplus下建用户: 1.以dba身份登陆SQLplus: [oracle ...

  6. JS:call()和apply的区别

    每个函数都包含两个非继承而来的方法:call()和apply(); call()方法:参数,第一个是作用域中调用函数(this),其余是参数直接传给函数 扩大作用域,传递参数时,参数必须逐个列出. w ...

  7. 【BZOJ3669】[Noi2014]魔法森林 LCT

    终于不是裸的LCT了...然而一开始一眼看上去这是kruskal..不对,题目要求1->n的路径上的每个点的两个最大权值和最小,这样便可以用LCT来维护一个最小生成路(瞎编的...),先以a为关 ...

  8. RAC初体验

    什么是RAC? 几乎每一篇介绍RAC的文章开头都是这么一个问题.我这篇文章是写给新手(包括我自己)看的,所以这个问题更是无法忽视. 简单的说,RAC就是一个第三方库,他可以大大简化你的代码过程. 官方 ...

  9. JS创建缩略图

    <script language="javascript"> //显示缩略图 function DrawImage(ImgD,width_s,height_s){ /* ...

  10. Twentydaysgone

    这个暑假,在学校呆了一个月,考了两次科目二,被驾校坑了五百块,四级又挂了,段位差点掉到白银 参加二十多天工作室的培训,学长直接带着做itheima的某某安全卫士,跟着视频也迷迷瞪瞪敲完了代码,一知半解 ...