借調試宏的設計,梳理下C語言宏的用法函數
嵌入式設備基本會配置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驅動模塊,但願在調試時打印調試信息,而產品代碼中不顯示調試信息。code
#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宏定義ip
#define DRV_DEBUG 0
固然也能夠直接這樣定義字符串
#define DRV_PRINT printf
可是若是宏調用了多個參數:編譯器
void foo() { DRV_PRINT("Driver Initialize Success: ver %d.%d !", 1, 2); }
產品代碼中的#define DRV_PRINT(x)
將編譯錯誤!產品
怎麼辦?一種處女座確定接受不了的作法,多加對括號
it
void foo() { DRV_PRINT(("Driver Initialize Success: ver %d.%d !", 1, 2)); }
無論是調試代碼仍是產品代碼,編譯都OK
#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
內核代碼裏就是這樣乾的!
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++卻不兼容了
有時候,某個模塊,有輸入跟蹤信息,輸出信息,錯誤信息等,若是我想單獨打開某部分信息,能夠這樣設計
#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,多多益善!