• C语言打印日志0718


    1、__FUNCTION__简介

    DATE 当前日期,一个以 “MMM DD YYYY” 格式表示的字符串常量

    TIME 当前时间,一个以 “HH:MM:SS” 格式表示的字符串常量。

    FILE 这会包含当前文件名,一个字符串常量。

    LINE 这会包含当前行号,一个十进制常量。

    STDC 当编译器以 ANSI 标准编译时,则定义为 1;判断该文件是不是标准 C 程序。

    FUNCTION 程序预编译时预编译器将用所在的函数名,返回值是字符串;

    2、实例

    int main() {
        printf("server start\r\n");
        printf("file:\"%s\"\nline: %d\nfunction: %s\n", __FILE__, __LINE__,__FUNCTION__);
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    结果:
    在这里插入图片描述

    3、第一版 最简单的情况无参数

    宏定义:

    #define __DEBUG //注释改语句,则关闭日志打印
    
     #ifdef __DEBUG 
     #define DEBUG(info)    printf(info) //序号1
     #else
     #define DEBUG(info)   //序号2
     #endif
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    主函数:

    int main() {
        DEBUG("server start\r\n");
        NetClientInit(NetClintRecv);
        return 0;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    1、没有注释
    在这里插入图片描述
    2、注释了,就不会打印
    在这里插入图片描述
    关于c语言中条件编译相关的预编译指令:

    #define 定义一个预处理宏
    #undef 取消宏的定义

    #if 编译预处理中的条件命令,相当于C语法中的if语句
    #ifdef 判断某个宏是否被定义,若已定义,执行随后的语句
    #ifndef 与#ifdef相反,判断某个宏是否未被定义
    #elif 若#if, #ifdef, #ifndef或前面的#elif条件不满足,则执行#elif之后的语句,相当于C语法中的else-if
    #else 与#if, #ifdef, #ifndef对应, 若这些条件不满足,则执行#else之后的语句,相当于C语法中的else
    #endif #if, #ifdef, #ifndef这些条件命令的结束标志. defined  与#if, #elif配合使用,判断某个宏是否被定义

    如果没有注释,则执行序号1,注释后,就是没有定义,执行序号2.

    4、第二版可变参数数目

    宏定义:

    #define __DEBUG 
    
     #ifdef __DEBUG
     #define xxxlog(format, ...) printf(format, ##__VA_ARGS__)
     #else
     #define xxxlog(format, ...)
     #endif
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    主函数:

    int main() {
        DEBUG("server start\r\n");
        NetClientInit(NetClintRecv);
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    没有注释结果:
    在这里插入图片描述

    注释结果:
    在这里插入图片描述

    添加参数,打开注释结果:
    在这里插入图片描述
    主函数:

    int main() {
        DEBUG("server start\r\n");
        uint8_t a = 10;
        uint8_t b = 99;
        DEBUG("a = %d\r\n",a);
        DEBUG("b = %d\r\n",b);
        DEBUG("a = %d, b = %d\r\n",a, b);
        NetClientInit(NetClintRecv);
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    来复习一下文章最开始介绍的功能
    主函数:

    int main() {
        DEBUG("server start\r\n");
        DEBUG("file:\"%s\"\nline: %d\nfunction: %s\n", __FILE__, __LINE__,__FUNCTION__);
        uint8_t a = 10;
        uint8_t b = 99;
        DEBUG("a = %d\r\n",a);
        DEBUG("b = %d\r\n",b);
        DEBUG("a = %d, b = %d\r\n",a, b);
        NetClientInit(NetClintRecv);
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    结果:
    在这里插入图片描述

    5、第三版:有层次的打印日志

    创建一个.h文件,所有的文件分为五级
    具体的优先级对应结构体:

    //定义日志级别
    typedef enum {
    LOG_LEVEL_OFF=0,
    LOG_LEVEL_FATAL,
    LOG_LEVEL_ERR,
    LOG_LEVEL_WARN,
    LOG_LEVEL_INFO,
    LOG_LEVEL_DEBUG,
    LOG_LEVEL_ALL
    }LOG_LEVEL;

    #ifndef APP_PUBLIC_LOGGER_H_
    #define APP_PUBLIC_LOGGER_H_
    
    #define __DEBUG   //日志模块总开关,注释掉将关闭日志输出
    
    #ifdef __DEBUG
        #define DEBUG(format, ...) printf (format, ##__VA_ARGS__)
    #else
        #define DEBUG(format, ...)
    #endif
    
    //定义日志级别
    typedef enum  {    
        LOG_LEVEL_OFF=0,
        LOG_LEVEL_FATAL,
        LOG_LEVEL_ERR,
        LOG_LEVEL_WARN,
        LOG_LEVEL_INFO,
        LOG_LEVEL_DEBUG,
        LOG_LEVEL_ALL
    }LOG_LEVEL;
    
    #define log_fatal(level,format, ...) \
        do { \
             if(level>=LOG_LEVEL_FATAL)\
               DEBUG("\n->FATAL @ FUNC:%s FILE:%s LINE:%d \n" format "\n",\
                         __func__, __FILE__, __LINE__, ##__VA_ARGS__ );\
        } while (0)
    
    #define log_err(level,format, ...) \
        do { \
             if(level>=LOG_LEVEL_ERR)\
               DEBUG("\n->ERR   @ FUNC:%s FILE:%s LINE:%d \n" format "\n",\
                         __func__, __FILE__, __LINE__, ##__VA_ARGS__ );\
        } while (0)
    
    #define log_warn(level,format, ...) \
        do { \
             if(level>=LOG_LEVEL_WARN)\
               DEBUG("\n->WARN  @ FUNC:%s \n" format "\n",__func__, ##__VA_ARGS__ );\
        } while (0)
    
    #define log_info(level,format, ...) \
        do { \
             if(level>=LOG_LEVEL_INFO)\
               DEBUG("\n->INFO  \n"format"\n",##__VA_ARGS__ );\
        } while (0)
    
    #define log_debug(level,format, ...) \
        do { \
             if(level>=LOG_LEVEL_ALL)\
               DEBUG("\n->DEBUG \n"format"\n",##__VA_ARGS__ );\
        } while (0)
    
    #endif /* APP_PUBLIC_LOGGER_H_ */
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56

    主函数调用:

    int main() {
        DEBUG("server start\r\n");
        static LOG_LEVEL logger=LOG_LEVEL_ALL;//模块日志输出级别
        DEBUG("file:\"%s\"\nline: %d\nfunction: %s\n", __FILE__, __LINE__,__FUNCTION__);
        log_fatal(logger,"this is a err %d ",-1);
        log_err(logger,"this is a err %d ",-1);
        log_warn(logger,"%s","this is a warn");
        log_info(logger,"this is a info");
        log_debug(logger,"this is a debug");
        NetClientInit(NetClintRecv);
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    需要打印那个级别的日志就改写logger的值,
    logger=LOG_LEVEL_ALL结果:
    在这里插入图片描述
    logger=LOG_LEVEL_WARN结果:
    在这里插入图片描述
    参考资料:
    1、C语言 FUNCTION - C语言零基础入门教程
    2、C使用宏定义封装printf实现日志功能
    3、条件编译#ifdef的妙用详解_透彻

    #ifndef APP_PUBLIC_LOGGER_H_
    #define APP_PUBLIC_LOGGER_H_
    
    #define __DEBUG   //日志模块总开关,注释掉将关闭日志输出
    
    #ifdef __DEBUG
        #define DEBUG(format, ...) printf (format, ##__VA_ARGS__)
    #else
        #define DEBUG(format, ...)
    #endif
    
    //定义日志级别
    typedef enum  {    
        LOG_LEVEL_OFF=0,
        LOG_LEVEL_PRINFT,
        LOG_LEVEL_INFO,
        LOG_LEVEL_DEBUG,
        LOG_LEVEL_ALL
    }LOG_LEVEL;
    
    LOG_LEVEL logprintf;
    
    #define log_debug(level,format, ...) \
        do { \
             if(level>=LOG_LEVEL_DEBUG)\
               DEBUG("\n->DEBUG @ FUNC:%s FILE:%s LINE:%d \n" format "\n",\
                         __func__, __FILE__, __LINE__, ##__VA_ARGS__ );\
        } while (0)
    
    #define log_info(level,format, ...) \
        do { \
             if(level>=LOG_LEVEL_INFO)\
               DEBUG("\n->INFO   @ FUNC:%s LINE:%d \n" format "\n",\
                         __func__, __LINE__, ##__VA_ARGS__ );\
        } while (0)
    
    #define log_printf(level,format, ...) \
        do { \
             if(level>=LOG_LEVEL_PRINFT)\
               DEBUG("\n->PRINTF  @ FUNC:%s \n" format "\n",__func__, ##__VA_ARGS__ );\
        } while (0)
    
    
    
    #endif /* APP_PUBLIC_LOGGER_H_ */
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
  • 相关阅读:
    2023年R1快开门式压力容器操作证模拟考试题库及R1快开门式压力容器操作理论考试试题
    【大厂面试重点(程序环境和预处理以及C语言不能函数重载但C++却可以的原理分析)】
    [附源码]SSM计算机毕业设计中小学微课学习系统JAVA
    面试官:小伙子,说说C/C++是如何进行内存管理的?我:……
    计算机毕业设计ssm法律在线咨询系统ds684系统+程序+源码+lw+远程部署
    竞赛 多目标跟踪算法 实时检测 - opencv 深度学习 机器视觉
    js常用方法
    android pdf框架-4,分析vudroid源码2
    [Android]问题解决-Device must be bootloader unlocked
    【Java八股文总结】之异常
  • 原文地址:https://blog.csdn.net/qq_43441284/article/details/126399912