前言
一般来说,初学编程者所写的第一个程序,就是使用printf打印“hello world”。其实printf的功效远不只这些,在程序调试方面,printf也有非常大的用处。
“蜗蜗”在接触linux driver开发之前,学习过桌面程序开发(如turbo c、visual c等),也从事了一段时间的嵌入式软件开发。这些开发有一个共同点,对调试工具非常依赖,如桌面程序的debugger(调试器)、嵌入式开发的仿真器(jtag等)。还依稀记得,刚工作时,为了插空使用仿真器,不得不趁周末别人不工作时加班使用。直到后来从事linux driver开发、见识到了printk的魅力之后,多年来,就再也没有使用过仿真器或者调试器了。
下面我就总结一下使用日志打印辅助debug的心得。
日志打印的注意事项
在编写程序后,我们可以随手在需要的地方加入打印信息,同时需要考虑如下事项:
1. 日志输出是有代价的,特别是在嵌入式系统,或者对执行时序要求较高的应用场景。因此
a) 只有在需要的地方加入,不能滥用
b) 一定要有一个全局的开关,在不需要或者产品发布的时候,关闭输出,或者降低日志输出的频率
2. 日志输出需要有优先级控制,例如:发生错误时的日志优先级最高,一般都要输出;一些重要的提示,优先级中等,可能会在debug版的软件中打开;一些不重要的提示,可能只会在需要的时候(例如跟踪bug)打开
3. 不要直接使用printf(或者printk)。日志输出的目标是多样的,例如通过printf输出到屏幕、通过串口输出到串口调试助手、通过文件操作写入到文件等等。要通过重定义的方式,将所有的日志输出指令定义到合适的输出路径,当需要修改输出路径的时候,只要修改重定义的部分即可。否则需要在整个代码中修改,就麻烦了
4. 最好为每个软件模块提供单独的日志输出开关,以增加调试的灵活性
5. 很多时候,日志输出语句,可以部分代替代码注释的功能
日志打印的实现
结合上面的注意事项,我们可以按照如下步骤实现一个小型的日志输出系统。
step1. 新建debug.h(如果只是在pc上使用printf,则只需要一个头文件即可。如果有需要文件或者串口操作,可以在这个基础上增加debug.c,这里暂时不再描述)
step2. 定义一个宏开关,用于控制日志输出的开关
/*
* debug control, you can switch on (delete 'x' suffix)
* to enable log output and assert mechanism
*/
#define config_enable_debug
step3. 定义err、info、debug三个日志级别
/*
* debug level,
* if is debug_level_disable, no log is allowed output,
* if is debug_level_err, only err is allowed output,
* if is debug_level_info, err and info are allowed output,
* if is debug_level_debug, all log are allowed output,
*/
enum debug_level {
debug_level_disable = 0,
debug_level_err,
debug_level_info,
debug_level_debug
};
step4. 如果使用系统的printf,需要包含stdio.h,并将printf重定义为print(无论是windows还是linux,皆是如此,如果是嵌入式平台,可以自定义print接口)
/* it can be change to others, such as file operations */
#include
#define print printf
step5. 定义一个宏,用于定义日志输出级别
/*
* the macro to set debug level, you should call it
* once in the files you need use debug system
*/
#define debug_set_level(x) static int debug = x
需要在每一个需要日志输出的c文件中调用,如下:
/*
* define the debug level of this file,
* please see 'debug.h' for detail info
*/
debug_set_level(debug_level_err);
step6. 定义assert、err、info、debug等宏
#define assert() \
do { \
print(assert: %s %s %d, \
__file__, __function__, __line__); \
while (1); \
} while (0)
#define err(...) \
do { \
if (debug >= debug_level_err) { \
print(__va_args__); \
} \
} while (0)
…
step7. 在需要日志输出的c文件中,包含debug.h,并定义所需的日志级别。就可以在需要的时候输出日志信息了
debug_test.c
-----------------------------------------------------
#include debug.h
/*
* define the debug level of this file,
* please see 'debug.h' for detail info
*/
debug_set_level(debug_level_err);
int main(void) {
err(this is a error message\n);
info(this is a info message\n);
debug(this is a debug message\n);
assert();
return 0;
}
step8. 可以根据需要,修改容许输出的日志级别
2021世界机器人大会开幕 共享科技盛宴
小米6最新消息《小米6 P谍照曝光 机身厚度有点感人》
高分辨率压力传感器助力Fitbit Ultra跟踪爬楼梯功能
iphone14与iPhone15的参数对比:摄像头
存算一体:内核架构创新,打破算力能效极限
Linux用日志打印的方式调试程序
分析:电机的冷却方式及其代号
压敏电阻热敏电阻的包封区别
小米正式带来一项全新的技术:一指连小米UWB技术
缺芯的影响有多大?对汽车产业并没有想象大
Versal系列芯片三个产品的基础知识
普通车床的组成和传动系统
可穿戴技术在医疗健康领域中的应用趋势
黑鲨游戏手机2更新了性能全开烧鸡模式性能跑分轻松破40万
Linux可用的事件选择器编码
单差分最简OCL功放,simple OCL amplifier
锂电产业链正在上演新一轮资本扩张行动
realme进军欧洲高端市场,5G旗舰+AloT双驱动震撼来袭
一文详解电子电路的安装布局
RISC-V探索之路 AIoT时代势如破竹