淺析在C/C++中如何寫(xiě)調(diào)試宏
1. 調(diào)試宏以及測(cè)試
在寫(xiě)代碼時(shí),不可避免需要打印提示、警告、錯(cuò)誤等信息,且要靈活控制打印信息的級(jí)別。另外,還有可能需要使用宏來(lái)控制代碼段(主要是調(diào)試代碼段)是否執(zhí)行。為此,本文提供一種調(diào)試宏定義方案,包括打印字符串信息LOG1
宏和格式化打印LOG2
宏,且能通過(guò)宏控制代碼段執(zhí)行。完整代碼如下:
#ifndef __DEBUG_H__ #define __DEBUG_H__ #include <iostream> #include <string> #include <stdio.h> // 定義日志級(jí)別枚舉 enum LogLevel { DEBUG, INFO, WARN, ERROR, FATAL }; // 全局日志級(jí)別變量聲明 extern LogLevel globalLogLevel; // 定義日志宏1 #define LOG1(level, message) do { \ if (level >= globalLogLevel) { \ std::cout << "[" #level "] " << __func__ << ":" << __LINE__ << " " << message << std::endl; \ } \ } while (0) // 定義日志宏2 // stdout帶緩沖,按行刷新,fflush(stdout)強(qiáng)制刷新 // stderr不帶緩沖,立刻刷新到屏幕 #define LOG2(level, format, args...) do { \ if (level >= globalLogLevel) { \ fprintf(stderr, "[" #level "] %s:%d " format "\r\n", __func__, __LINE__, ##args); \ } \ } while (0) // 通過(guò)宏控制調(diào)試代碼是否執(zhí)行 #define EXECUTE #ifdef EXECUTE #define DEBUG_EXECUTE(code) [code] #else #define DEBUG_EXECUTE(code) #endif #endif
在main文件進(jìn)行宏定義測(cè)試,需要定義全局日志級(jí)別,以INFO
為例,則DEBUG
信息不打印。測(cè)試文件如下:
#include "debug.h" // 全局日志級(jí)別變量定義 LogLevel globalLogLevel = INFO; int main(void) { LOG1(DEBUG, "DEBUG message"); LOG1(INFO, "INFO message"); LOG1(WARN, "WARN message"); LOG1(ERROR, "ERROR message"); LOG1(FATAL, "FATAL message"); int num = 10; LOG2(INFO, "num: %d", num); DEBUG_EXECUTE( LOG2(ERROR, "debug execute"); ) }
2. 宏定義小細(xì)節(jié)
2.1 #和##
兩者都是預(yù)處理運(yùn)算符
- #是字符串化運(yùn)算符,將其后的宏參數(shù)轉(zhuǎn)換為用雙括號(hào)括起來(lái)的字符串。
- ##是符號(hào)連接運(yùn)算符,用于連接兩個(gè)標(biāo)記(標(biāo)記不一定是宏變量,可以是標(biāo)識(shí)符、關(guān)鍵字、數(shù)字、字符串、運(yùn)算符)為一個(gè)標(biāo)記。
在第一章中使用#把日志級(jí)別變量轉(zhuǎn)為字符串,##的作用是在可變參數(shù)為0是,刪除前面的逗號(hào),只輸出字符串。
2.2 do while(0)
do while常用來(lái)做循環(huán),而while參數(shù)為0,表示這樣的代碼肯定不是做循環(huán)用的,它有什么用呢?
輔助定義復(fù)雜宏,避免宏替換出錯(cuò)
假如你定義一個(gè)這樣宏,本意是調(diào)用DOSOMETHING
時(shí)執(zhí)行兩個(gè)函數(shù)。
#define DOSOMETHING() \ func1(); \ func2();
但在類似如下使用宏的代碼,宏展開(kāi)時(shí)func2
無(wú)視判斷條件都會(huì)執(zhí)行。
if (0 < a) DOSOMETHING(); // 宏展開(kāi)后 if (0 < a) func1(); func2();
優(yōu)化一下,用{}
包裹宏是否可行呢?如下:
#define DOSOMETHING() { \ func1(); \ func2();}
由于我們寫(xiě)代碼習(xí)慣在語(yǔ)句后加分號(hào),你可能會(huì)有如下的展開(kāi)后編譯錯(cuò)誤。
if(0 < a) DOSOMETHING(); else ... // 宏展開(kāi)后 if(0 < a) { func1(); func2(); }; // 錯(cuò)誤處 else ...
而do while (0)則能避免這些錯(cuò)誤,所以復(fù)雜宏定義經(jīng)常使用它。
消除分支語(yǔ)句或者goto語(yǔ)句,提高代碼的易讀性
如果在一個(gè)函數(shù)中開(kāi)始要分配一些資源,然后在中途執(zhí)行過(guò)程中如果遇到錯(cuò)誤則退出函數(shù),當(dāng)然,退出前先釋放資源,我們的代碼可能是這樣:
bool Execute() { // 分配資源 int *p = new int; bool bOk(true); // 執(zhí)行并進(jìn)行錯(cuò)誤處理 bOk = func1(); if(!bOk) { delete p; p = NULL; return false; } bOk = func2(); if(!bOk) { delete p; p = NULL; return false; } // 執(zhí)行成功,釋放資源并返回 delete p; p = NULL; return true; }
這里一個(gè)最大的問(wèn)題就是代碼的冗余,而且我每增加一個(gè)操作,就需要做相應(yīng)的錯(cuò)誤處理,非常不靈活。于是我們想到了goto
:
bool Execute() { // 分配資源 int *p = new int; bool bOk(true); // 執(zhí)行并進(jìn)行錯(cuò)誤處理 bOk = func1(); if(!bOk) goto errorhandle; bOk = func2(); if(!bOk) goto errorhandle; // 執(zhí)行成功,釋放資源并返回 delete p; p = NULL; return true; errorhandle: delete p; p = NULL; return false; }
代碼冗余是消除了,但是我們引入了C++
中身份比較微妙的goto
語(yǔ)句,雖然正確的使用goto
可以大大提高程序的靈活性與簡(jiǎn)潔性,但太靈活的東西往往是很危險(xiǎn)的,它會(huì)讓我們的程序捉摸不定,那么怎么才能避免使用goto
語(yǔ)句,又能消除代碼冗余呢,請(qǐng)看do...while(0)
:
bool Execute() { // 分配資源 int *p = new int; bool bOk(true); do { // 執(zhí)行并進(jìn)行錯(cuò)誤處理 bOk = func1(); if(!bOk) break; bOk = func2(); if(!bOk) break; }while(0); // 釋放資源 delete p; p = NULL; return bOk; }
使用代碼塊,代碼塊內(nèi)定義變量,不用考慮變量重復(fù)問(wèn)題
顯而易見(jiàn)。
到此這篇關(guān)于淺析在C/C++中如何寫(xiě)調(diào)試宏 的文章就介紹到這了,更多相關(guān)C++寫(xiě)調(diào)試宏 內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C++實(shí)現(xiàn)頭文件保護(hù)機(jī)制
頭文件保護(hù)機(jī)制是一種防止頭文件被重復(fù)包含的技術(shù),它主要借助 #ifndef、#define 和 #endif 這些預(yù)處理指令來(lái)達(dá)成,本文就來(lái)詳細(xì)的介紹一下,感興趣的可以了解一下2025-04-04C語(yǔ)言入門(mén)篇--局部全局變量的作用域及生命周期
本篇文章是c語(yǔ)言基礎(chǔ)篇,本文對(duì)初識(shí)c語(yǔ)言的變量、局部全局變量的作用域及生命周期做了簡(jiǎn)要的概述,希望可以幫助大家快速入門(mén)c語(yǔ)言的世界,更好的理解c語(yǔ)言2021-08-08c++ vector模擬實(shí)現(xiàn)的全過(guò)程
這篇文章主要給大家介紹了關(guān)于c++ vector的模擬實(shí)現(xiàn)過(guò)程,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-04-04C語(yǔ)言學(xué)生信息管理系統(tǒng)設(shè)計(jì)與實(shí)現(xiàn)
這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言學(xué)生信息管理系統(tǒng)設(shè)計(jì)與實(shí)現(xiàn),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-01-01