2010-03-24 64 views
8

在調試模式或當我做測試,我需要打印大量的各種信息,所以我用這個方法:如何分離調試和發佈模式代碼

#ifdef TESTING 
// code with lots of debugging info 
#else 
// clean code only 
#endif // TESTING` 

這是一個很好的方法,或還有其他簡單而優雅的方法嗎?

可是這樣一來,我反覆在兩個地方相同的代碼,如果有什麼要稍後在代碼上改變,我必須這樣做,在這兩個地方,這是耗時且容易出錯。

謝謝。

我使用MS Visual Studio中。

回答

17

你可以使用宏來打印調試信息,然後在發佈版本,定義宏爲空。

例如,

#ifdef _DEBUG 
#define DEBUG_PRINT(x) printf(x); 
#else 
#define DEBUG_PRINT(x) 
#endif 

使用這種方法,你也可以添加更多的信息,如

__LINE__ 
__FILE__ 
自動

的調試信息。

+1

宏是不好的C++風格。 – 2010-03-24 15:17:12

+0

也許,但問題是標記爲C和C++。 – 2010-03-24 15:21:24

+0

我不同意Alexey,我用C++和宏編寫了多年,沒有任何問題。也許是不好的C++風格,對於不知道他們做什麼的壞程序員,但只有宏才能做一些非常困難的想法。使用許多方法的自由並不是很差:) – Aristos 2010-03-24 15:25:47

2

使用定義一樣,對包括報頭的

#ifdef TESTING 
#define DEBUG_INFOS(_X_) CallYourDebugFunction(_X_) 
#else 
#define DEBUG_INFOS(_X_) ((void)0) 
#endif 

,然後只用這對你的代碼

... 
DEBUG_INFOS("infos what ever"); 
RestOfWork(); 
... 

您還可以使用並搜索ASSERTTRACE宏並使用sysinternals中的DebugView從跟蹤讀取輸出實時,或使用ASSERT跟蹤問題。 ASSERT和TRACE做類似的工作,你可以從他們那裏得到想法。

評論:我用的是測試聲明,因爲我看到的問題。

5

一次寫入

#ifdef _DEBUG 
const bool is_debig = true; 
#else 
const bool is_debig = false; 
#endif 

然後

template<bool debug> 
struct TemplateDebugHelper { 
    void PrintDebugInfo(const char*); 
    void CalcTime(...); 
    void OutputInfoToFile(...); 
    /// ..... 
}; 

// Empty inline specialization 
template<> 
struct TemplateDebugHelper<false> { 
    void PrintDebugInfo(const char*) {} // Empty body 
    void CalcTime(...) {} // Empty body 
    void OutputInfoToFile(...) {} // Empty body 
    /// ..... 
}; 

typedef TemplateDebugHelper<is_debug> DebugHelper; 

DebugHelper global_debug_helper; 

int main() 
{ 
    global_debug_helper.PrintDebugInfo("Info"); // Works only for is_debug=true 
} 
+0

我能問你如果留在編譯後的文件的任何代碼,在釋放模式? – Aristos 2010-03-24 15:23:21

+0

在最壞情況下,它會豆空功能cal。但是,由於代碼必須可供編譯器使用,根據我的經驗,即使這樣做也會得到優化。 – 2010-03-24 15:33:51

+1

我喜歡這個答案,只是我的經驗是,如果一個程序員寫「global_debug_helper.PrintDebugInfo」他不會去打擾。我一般使用短全部大寫所以它們很容易寫,但很容易發現: BUG.OUT(「信息」); – swestrup 2010-03-24 15:37:20

1

您可以使用類似boost::log設置嚴重級別到你所需要的人。

void init() 
{ 
    logging::core::get()->set_filter 
    (
     flt::attr<logging::trivial::severity_level>("Severity") >= logging::trivial::info 
    ); 
} 

int main(int, char*[]) 
{ 
    init(); 

    BOOST_LOG_TRIVIAL(trace) << "A trace severity message"; 
    BOOST_LOG_TRIVIAL(debug) << "A debug severity message"; 
    BOOST_LOG_TRIVIAL(info) << "An informational severity message"; 
    BOOST_LOG_TRIVIAL(warning) << "A warning severity message"; 
    BOOST_LOG_TRIVIAL(error) << "An error severity message"; 
    BOOST_LOG_TRIVIAL(fatal) << "A fatal severity message"; 
} 

我認爲pantheios也有類似的東西。而不是滾動您自己的日誌

2

使用Log4Cxx。 Log4Cxx包高度可配置,支持基於重要性/嚴重性的不同級別的日誌記錄,並支持多種形式的輸出。

另外,除非是必須超優化的非常關鍵的代碼,我會建議留下記錄語句(假設你使用Log4Cxx)在你的代碼,而只是調低日誌記錄級別。這樣,可以動態啓用日誌記錄,如果其中一位用戶遇到難以複製的錯誤,那麼這可能非常有用,只需指導他們如何配置更高的日誌記錄級別即可。如果您完全忽略了可執行文件的日誌記錄,那麼無法在現場獲得有價值的調試輸出。

+1

這個。 在我的團隊項目,我們發現在跟蹤消息編譯並不會對性能產生noticable影響,除非我們真正啓用跟蹤和log4xxx框架的美是你可以做的一些日誌來源,但不是別人,依賴根據你想要的目標。 有我們的代碼的一些地方的參數跟蹤日誌調用是計算價格昂貴;對於這些,我們只需要調用記錄儀:: isEnabledFor(LogLevelTrace)來檢測跟蹤是對一個給定的記錄時;如果是這樣,我們建立了昂貴的指定參數和記錄跟蹤消息,否則我們不要管它。 – anelson 2010-03-24 21:26:50

+0

@anelson,你爲什麼不使用LOG4CXX_TRACE(記錄儀,MSG)?我相信宏已經爲你檢查。 – 2010-03-24 23:11:55

0

我在C. 編寫嵌入式系統在我的節目我使用下面的宏:

 
#define _L log_stamp(__FILE__, __LINE__) 

#define _LS(a) log_string(a) 

#define _LI(a) log_long(a) 

#define _LA(a,l) log_array(a,l) 

#define _LH(a) log_hex(a) 

#define _LC(a) log_char(a) 

#define ASSERT(con) log_assert(__FILE__, __LINE__, con) 

當我製作發行版,我乾脆關掉的#define DEBUG指令和所有宏變空。 請注意,它不會消耗發行版本中的任何CPU週期和內存。 宏是保存日誌信息的唯一方法:日誌記錄已完成 (文件和行號)。

如果我需要這個信息的使用: _L;_LS("this is a log message number ");_LI(5);

否則不_L指令。

0

有一個簡單的方法,這與大多數編譯器的工作原理:

#ifdef TESTING 
    #define DPRINTF(args)  printf args 
#else 
    #define DPRINTF(args)  ((void)0) 
#endif 

接下來,在源代碼中,你應該使用它作爲:

DPRINTF(("Debug: value a = %d, value b = %d\n", a, b)); 

的缺點是,你必須使用雙括號,但在舊的C和C++ 標準可變參數宏不受支持(僅作爲編譯器擴展)。