• hizei c++ 试听课程知识点 day2


    一、实现调试信息log日志打印功能

      调试信息  第一步需要定位程序中的问题。

    二  预处理命令   宏定义   以#开头     功能字符串替换   主要作用在预处理阶段

      c源代码-----》(预处理阶段)待编译源码----》(编译阶段)目标文件----》(链接)可执行程序

      可执行程序的功能由第二步的待编译源码决定的    而不是c源代码

      ************************g++ -E main.cpp   查看待编译源代码的命令    可以重定向到文件便于查看***************

    定义符号常量

        #define   pi 3.1415926

      定义傻瓜表达式

        #define MAX(a,b) (a)>(b)?(a):(b)

      定义代码段

        #define p(a){printf("%d ",a)}   宏定义需要写在一行之内,如果不能显示下   需要 “” 连接符号

          定义有参数的宏

        #define S(a,b)  a*b         宏定义

        printf("S(3,4)=%d ",s(3,4));     替换为3*4

        printf("S(int,p)=%d ",s(3,4));   替换为 int *p  在这里是通过宏的方式定义指针变量。

             S(int,p)=&n;      相当于  int *p=&n    定义指针

      以上为基础宏定义

     预处理命令   include  头文件中的内容  进入到待编译文件中展开   所以源文件中包含的头文件越多,预编译生成的待编译文件内容越多。

    三:预处理命令---预定义的宏                编译器的内置宏

      __DATE__         日期 

      __TIME__     时间

      __LINE__    行号

      —FILE__    文件名

      __func__    函数名

      —PRETTY_FUNCTION  更详细的函数信息

      printf("__FILE__=%S ",__file__);         输出:main.cpp

      printf("__LINE__=%d ",__LINE__);    输出:30   当前行号

      

    四:举例 LOG宏   实现日志打印功能

    1.args...

    gcc编译器中的cpp预编译器     支持args...  

    第一个参数传递给frm    第二个开始传递给args... 

    2.##args     将args...中的多个参数  串联起来     ...代表变参     #的作用为连接操作   如果下面的printf(frm,##args)  中的##去掉   则编译不通过。

    3.#frm    将frm传递进来的内容以字符串的形式输出

    #include <iostream>
    #define LOG(frm,args...){
        printf("[%s:%s:%d]",__FILE__,__func__,__LINE__);
        printf(frm,##args);
        printf("
    ");
    }
    using namespace std;
    void test(){
        LOG("hello world");
        return;
    }
    
    int main()
    {
        int a=123;
        LOG("a=%d=%d",a,2*a);
        LOG("hello world");
        test();
        return 0;
    }
    

    举例:

    例子1

    #define DBG_OUTPUT(fmt,args...printf("CK File[%s:%s(%d)]:" fmt   " "__FILE__,__FUNCTION____LINE__##args)      //宏定义

    DBG_OUTPUT("j[%d]k[%d]" , j,k);    //实际调用

    实际输出:CK File   **  j[-15]k[241]

    例子2

    #define DBG_OUTPUT(fmt,args...) printf("CK File[%s:%s(%d)]:" #fmt   " ", __FILE__,__FUNCTION__, __LINE__, ##args)

    DBG_OUTPUT(j[%d]k[%d], j, k);

      

    gcc的option  -E   为向标准输入输出中,输出预编译结果。

    gcc   -E  test.c >& test.i     生成编译结果  保存在test.i的文本文件中。   查看DBG_OUTPUT 语句的位置  看其被编译替换成什么

     两个参数连接时,可以允许参数的值为空。  这就是##的作用  

    上例中的 ##args,输入的参数可以为空;如果是args   输入的实参不能为空。

    举例:

      #define  CAT(a,b)   a##b

      hz=1000;

      CAT(h,z)=500;  //实际的结果是hz=500;

      printf("%d ",hz);//输出的结果为500

     如果不清楚 ,需要看待编译源代码:g++ -E main.cpp>>temp.cpp       重定向到temp.cpp   查看temp.cpp文件

    两个##的作用是允许前后两个参数为空。

    五:开发版和上线版的区别

    开发需要有调试信息

    上线不能有调试信息

    不改变代码的情况,需要使用预编译宏的方式进行总开关操作,来实现调试信息的显示和关闭。

    方法1:加入标记开关

    int log_flag=0;      //开关按钮  0 和1
    #define LOG(frm,args...) do {  //跳出局部作用域    从循环内部跳出
        if (log_flag==0) break;
        printf("[%s:%s:%d]",__FILE__,__func__,__LINE__);
        printf(frm,##args);
        printf("
    ");
    } while(0);
    

     需要打开则使得log_flag=1即可。

    方法2:

    预处理命令--条件式编译    主要在做代码剪裁。

    #ifdef DEBUG          是否定义了DEBUG宏

    #ifdef DEBUG  是否定义了DEBUG宏

    #if  MAX_N==5  宏MAX_N是否等于5

    #elif  MAX_N==4    否则宏MAX_N是否等于4

    #else

    #endif    条件片段需要以此为结尾

    举例:

    #ifdef DEBUG    如果定义DEBUG宏 代表需要调试程序  则执行下面的代码
    #define LOG(frm,args...){
        printf("[%s:%s:%d]",__FILE__,__func__,__LINE__);
        printf(frm,##args);
        printf("
    ");
    }
    #else       不调试程序信息  则执行下面的空代码
    #define  LOG(frm,args...)
    #endif
    

     如果在最前面,加入#define DEBUG   则显示调试信息     否则不显示

      编译命令中  加入DEBUG宏g++  -DDEBUG   log.cpp

    3.修改makefile文件

      all:

        g++  main.cpp

      debug:

        g++ -DDEBUG main.cpp

    在shell命令行中:

       make 就是执行all中的命令   相当于上线版

       make debug  就是执行带调试的命令。  相当于开发版

    4.调试信息提示    LOG等级信息

      等级信息

      info     error     debug     warning     fatal

       关闭某一个等级下的日志信息。

    5.日志输出变为多线程

    6.增加输出到文件中

      

      

      

      

      

      

      

      

      

      

      

  • 相关阅读:
    JDK1.5新特性,基础类库篇,调用外部命令类(ProcessBuilder)用法
    JDK1.5新特性,基础类库篇,格式化类(Formatter)用法
    JDK1.5新特性,语言篇
    几种常见排序算法之Java实现(插入排序、希尔排序、冒泡排序、快速排序、选择排序、归并排序)
    JSON概述及其在JavaScript与Java中的应用(整理)
    JavaScript:表单常用验证脚本(整理)
    JavaScript:零星知识
    浏览器脚本概述(整理)
    Angular
    Angular
  • 原文地址:https://www.cnblogs.com/dongguolei/p/13851277.html
Copyright © 2020-2023  润新知