C语言——设计printf调试宏

发布时间:2019-06-23 发布网站:脚本宝典
脚本宝典收集整理的这篇文章主要介绍了C语言——设计printf调试宏脚本宝典觉得挺不错的,现在分享给大家,也给大家做个参考。

前言

借调试宏的设计,梳理下c语言宏的用法

重定向PRintf打印

嵌入式设备基本会配置RS232串口作为调试IO接口,假设底层串口单字节输出函数为SERIAL_putchar(),利用fputc()和fputs()重定向printf函数

void fputc(int byte, FILE* stream)
{
    (void)stream;

    SERIAL_PutChar(byte);
}

void fputs(const char *pstr, FILE *stream)
{
    (void)stream;

    while(*pstr)
    {
        SERIAL_PutChar(*pstr++);
    }
}

这样在代码里面利用printf()函数输出的字符串都老老实实从调试串口出来

调试宏使用场景

某个C驱动模块,希望在调试时打印调试信息,而产品代码中不显示调试信息。

v1--单参数宏

#define DRV_DEBUG 1
#if DRV_DEBUG
    #define DRV_PRINT(x) printf(x)
#else
    #define DRV_PRINT(x) 
#endif

这个版本的DRV_PRINT(x)只能输出单变量——纯字符串

void foo()
{
    DRV_PRINT("Driver InITialize Success!");
}

不需要打印调试信息时,更改DRV_DEBUG宏定义

#define DRV_DEBUG 0

当然也可以直接这样定义

#@H_360_155@define DRV_PRINT printf

但是如果宏调用了多个参数:

void foo()
{
    DRV_PRINT("Driver Initialize Success: ver %d.%d !", 1, 2);
}

产品代码中的#define DRV_PRINT(x)将编译错误!

怎么办?一种处女座肯定接受不了的做法,多加对括号

void foo()
{
    DRV_PRINT(("Driver Initialize Success: ver %d.%d !", 1, 2));
}

不管是调试代码还是产品代码,编译都OK

v2--指定参数宏

#define DRV_DEBUG 1
#if DRV_DEBUG
    #define DRV_PRINT(fmt, val1, val2) printf(fmt, val1, val2)
#else
    #define DRV_PRINT(fmt, val1, val2) 
#endif

如果只需要打印一个变量,第2个参数用随意值填位,如

void foo()
{
    DRV_PRINT("Driver Initialize Success: ver %d !", val1, 2);
}

类似,如果有4个参数,就:

void foo()
{
    DRV_PRINT("Driver Initialize Success: ver %d !", val1, 2, 3, 4);
}

很傻,但是没办法:(,VxWorks 5.5内核代码里就是这样干的!

v3--参数数量可变宏

C90和C++中可将宏声明为接受可变数量的自变量,如ARM编译器是这样的:

#define DRV_DEBUG 1
#if DRV_DEBUG
    #define DRV_PRINT(fmt, ...) printf(fmt, __VA_argS__)
#else
    #define DRV_PRINT(fmt, ...) 
#endif

现在DRV_PRINT用法和printf完全一样了,这么爽的功能,C2000编译器却不支持!

题外话,注意这个特性C90支持,而C90是C++的一个子集,但是C99和C++却不兼容了

分层次LOG输出

有时候,某个模块,有输入跟踪信息,输出信息,错误信息等,如果我想单独打开某部分信息,可以这样设计

#define DRV_DEBUG 1
#define DRV_DEBUG_IN 0x0001
#define DRV_DEBUG_OUT 0x0002
#define DRV_DEBUG_ERR 0x0004
#define DRV_DEBUG_ALL 0xFFFF
#if DRV_DEBUG
        unsigned int drv_flags = DRV_DEBUG_ERR | DRV_DEBUG_OUT;
    #define DRV_PRINT(flag, fmt, ...) 
            do{
                if(drv_flags & flag){
                printf(fmt, __VA_ARGS__)}
            }while(0)
#else
    #define DRV_PRINT(fmt, ...) 
#endif

NOTE: 多行宏,注意换行前加

这样,我只打印OUT和ERR:

void drv_write(char* msg_out)
{
    DRV_PRINT(DRV_DEBUG_OUT, "Drivr write %s", msg_out); // 输出
        DRV_PRINT(DRV_DEBUG_ERR, "Drivr write %s", msg_out); // 输出
        DRV_PRINT(DRV_DEBUG_IN, "Drivr write %s", msg_out); // 不输出
}

进一步,可以设计针对整个系统不同模块的LOG输出控制!TCP/IP协议栈实现Lwip就是这么干的!

总结

在嵌入式C语言里面,运用printf调试宏,有助于事后分析,定位BUG,多多益善!

脚本宝典总结

以上是脚本宝典为你收集整理的C语言——设计printf调试宏全部内容,希望文章能够帮你解决C语言——设计printf调试宏所遇到的问题。

如果觉得脚本宝典网站内容还不错,欢迎将脚本宝典推荐好友。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。