设计printf调试宏
設計printf調試宏:在調試時打印調試信息,而產品代碼不顯示調試信息。
#define _DEBUG_ 0 #if _DEBUG_ #define ACCLOG(...) printf(__VA_ARGS__) #else #define ACCLOG(...) #endif在代碼中可以如下使用以上的定義:
ACCLOG("test car...\n");
ACCLOG("find card:%s\n", car_str);??
重定向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當然也可以直接這樣定義
#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_DEBUGunsigned 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, ...) #endifNOTE: 多行宏,注意換行前加\號
這樣,我只打印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,多多益善!
總結
以上是生活随笔為你收集整理的设计printf调试宏的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: STM32的SPI驱动代码
- 下一篇: STM32中stm32f0xx_flas