1. assert 函式

一般在做 trace 時,似乎比較少人用到 assert,assert 裡面放的判斷是,如果「不成立的話」,程式便不會繼續執行下去。以下述程式碼而言

  

#include <stdio.h>
#include <assert.h>
int main()
{
    int a=10, b=0;
    assert(!(b==0));
    printf("%d\n", a/b);
    return 0;
}

 

執行時將出現以下視窗 

DebugAssert (2).png    

console 那裡結果如下

Assertion failed: !(b==0), file d:\vctest\main.c, line 6

但這種方式,是不論為 release mode 或 debug mode,都會顯示此訊息。

一些書之 tips 裡,會提到,在做 release 時,將相關 debug 函式全都拿掉會是較好的做法。

意思是,當程式 release 給 client 時,所有 assert 都拿掉會較佳。

如此一來,debug 完,到時又把 assert 全拿掉又顯得費時,於是用一些條件式鍽譯技巧,

進行轉換。

 


 

 

2. 自定義 __degug.c , __debug.h

 

 

再加入

/* filename : __debug.h */

#ifndef __DEBUG_H__
#define __DEBUG_H__

#ifdef _DEBUG

void _trace(char *fmt, ...);

#define ASSERT(x) {if(!(x)) _asm{int 0x03}}
#define VERIFY(x) {if(!(x)) _asm{int 0x03}} 

#else
#define ASSERT(x)
#define VERIFY(x) x
#endif

#ifdef _DEBUG
#define TRACE _trace

#else
inline void _trace(LPCTSTR fmt, ...) { }
#define TRACE 1 ? (void)0 : _trace
#endif

#endif // __DEBUG_H__

 

/* filename : __debug.c */

#ifdef _DEBUG

#include <stdio.h>
#include <stdarg.h>
#include <windows.h>

void _trace(char *fmt, ...)
{
    char out[1024];
    va_list body;
    va_start(body, fmt);
    vsprintf(out, fmt, body);
    va_end(body); 
    OutputDebugString(out);
}
#endif

 

直接拿一個測試程式碼出來

 

#include <stdio.h>
#include "__debug.h"
int main()
{
    int a=10, b=0;
    ASSERT(!(b==0));
    printf("%d\n", a/b);
    return 0;
}

 

執行結果與上述相仿

DebugAssert (4).png

但這支測試程式碼之 ASSERT ,只在「偵錯」時有作用,在發佈出去「執行」時將不具作用。 

 


 

3. TRACE

  

上述 __debug.h 裡面還提到了 TRACE,一般新手在做 trace 時,

會以 printf 方式輸出到 console 視窗上面去,

這裡的 TRACE 則是直接將結果輸出到 IDE 裡的「輸出」視窗裡面去。

  

#include <stdio.h>
#include "__debug.h"

int main()
{
    int x=0, sum=0;
    for(x=0; x<=10; ++x) {
        sum+=x;
        TRACE("x=%d, sum=%d\n", x, sum);
    }
    return 0;
}

 

輸出結果在 console 視窗看不到,只會在 IDE 裡之「輸出視窗」看到結果

  

DebugTrace (3).png  

 

edisonx 發表在 痞客邦 PIXNET 留言(3) 人氣()


留言列表 (3)

發表留言
  • novus
  • 用函數實作 trace 有一些小小的缺點。其中之一是必須依賴 inline 機制才有辦法在 release build 徹底消除不必要的呼叫,這點對現代的編譯器都不是問題。另一個問題是參數裡面的運算式有可能會被執行。

    比較保險的作法應該是使用巨集配合 __VA_ARGS__ 實作,只是太舊的編譯器可能會無法支援。

    在 C++ 底下可以玩的把戲就很多了,我在這裡有提到一些後端輸出的程式庫
    http://novus.pixnet.net/blog/post/27548040

    改天我也來寫一篇介紹一下 debug 前端的介面好了
  • 感謝您的補充與提醒,我比較納悶的是,「參數裡面的運算式有可能會被執行」,這問題我想半天想不透為何可能會被執行。__VA_ARGS__ 這方式之前沒想過,有空會研究一下怎包出來做應用。連上了您的網站,有機會我也去借本 Applied C++: Practical Techniques for Building Better Software 出來看看好了。

    最後謝謝您的回覆,讓我知道了許多我不知道的缺點、技巧,再次感謝! *^_^*

    edisonx 於 2011/09/04 13:56 回覆

  • novus
  • trace 的部份我沒仔細看成是碼,應該是我說錯了

    關於實作上的一些考量可以參考
    http://www.jeffhung.net/blog/articles/jeffhung/1013/
    (我在最下面的 comment 就是你在這裡的作法,但我po出才發現犯了一個小小的錯誤,哈)


    其實我並不特別推薦Applied C++: Practical Techniques for Building Better Software 當中的方案,我比較推薦你去讀 google log 的原始碼,他可以作到非常細微的控制,像是讓某些模組在 release build仍然會輸出除錯資訊,另一些模組則完全關閉除錯。他還提供了獨立於 NDEBUG 的除錯層級,像是關閉所有 level 4 以下的除錯資訊,但以上的資訊仍然照常輸出。


  • 謝謝補充。感到很可惜回覆沒辦法按「讚」,這些回覆提到的東西對我幫助很大,再次感謝。

    edisonx 於 2011/09/04 16:25 回覆

  • 路人
  • 第一部分
    「但這種方式,是不論為 release mode 或 debug mode,都會顯示此訊息。」
    可以 #define NDEBUG 就可以當release version了 @@
    http://www.cplusplus.com/reference/cassert/assert/
  • 疑!之前沒注意到這點說明,謝謝提供。

    edisonx 於 2014/04/20 21:09 回覆

您尚未登入,將以訪客身份留言。亦可以上方服務帳號登入留言

請輸入暱稱 ( 最多顯示 6 個中文字元 )

請輸入標題 ( 最多顯示 9 個中文字元 )

請輸入內容 ( 最多 140 個中文字元 )

請輸入左方認證碼:

看不懂,換張圖

請輸入驗證碼