1. 程式人生 > >VS除錯以及Trace函式的用法

VS除錯以及Trace函式的用法

VC除錯入門

設定
為了除錯一個程式,首先必須使程式中包含除錯資訊。一般情況下,一個從AppWizard建立的工程中包含的Debug Configuration自動包含除錯資訊,但是是不是Debug版本並不是程式包含除錯資訊的決定因素,程式設計者可以在任意的Configuration中增加除錯資訊,包括Release版本。
為了增加除錯資訊,可以按照下述步驟進行:

  • 開啟Project settings對話方塊(可以通過快捷鍵ALT+F7開啟,也可以通過IDE選單Project/Settings開啟)
  • 選擇C/C++頁,Category中選擇general ,則出現一個Debug Info下拉列表框,可供選擇的除錯資訊 方式包括: 
     
    命令列
    Project settings 說明
    None 沒有除錯資訊
    /Zd Line Numbers Only 目標檔案或者可執行檔案中只包含全域性和匯出符號以及程式碼行資訊,不包含符號除錯資訊
    /Z7 C 7.0- Compatible 目標檔案或者可執行檔案中包含行號和所有符號除錯資訊,包括變數名及型別,函式及原型等
    /Zi Program Database 建立一個程式庫(PDB),包括型別資訊和符號除錯資訊。
    /ZI Program Database for Edit and Continue 除了前面/Zi的功能外,這個選項允許對程式碼進行除錯過程中的修改和繼續執行。這個選項同時使#pragma設定的優化功能無效
  • 選擇Link頁,選中複選框"Generate Debug Info",這個選項將使聯結器把除錯資訊寫進可執行檔案和DLL
  • 如果C/C++頁中設定了Program Database以上的選項,則Link incrementally可以選擇。選中這個選項,將使程式可以在上一次編譯的基礎上被編譯(即增量編譯),而不必每次都從頭開始編譯。

設定
為了除錯一個程式,首先必須使程式中包含除錯資訊。一般情況下,一個從AppWizard建立的工程中包含的Debug Configuration自動包含除錯資訊,但是是不是Debug版本並不是程式包含除錯資訊的決定因素,程式設計者可以在任意的Configuration中增加除錯資訊,包括Release版本。
為了增加除錯資訊,可以按照下述步驟進行:

  • 開啟Project settings對話方塊(可以通過快捷鍵ALT+F7開啟,也可以通過IDE選單Project/Settings開啟)
  • 選擇C/C++頁,Category中選擇general ,則出現一個Debug Info下拉列表框,可供選擇的除錯資訊 方式包括: 
     
    命令列 Project settings 說明
    None 沒有除錯資訊
    /Zd Line Numbers Only 目標檔案或者可執行檔案中只包含全域性和匯出符號以及程式碼行資訊,不包含符號除錯資訊
    /Z7 C 7.0- Compatible 目標檔案或者可執行檔案中包含行號和所有符號除錯資訊,包括變數名及型別,函式及原型等
    /Zi Program Database 建立一個程式庫(PDB),包括型別資訊和符號除錯資訊。
    /ZI Program Database for Edit and Continue 除了前面/Zi的功能外,這個選項允許對程式碼進行除錯過程中的修改和繼續執行。這個選項同時使#pragma設定的優化功能無效
  • 選擇Link頁,選中複選框"Generate Debug Info",這個選項將使聯結器把除錯資訊寫進可執行檔案和DLL
  • 如果C/C++頁中設定了Program Database以上的選項,則Link incrementally可以選擇。選中這個選項,將使程式可以在上一次編譯的基礎上被編譯(即增量編譯),而不必每次都從頭開始編譯。

 斷點
斷點是偵錯程式設定的一個程式碼位置。當程式執行到斷點時,程式中斷執行,回到偵錯程式。斷點是 最常用的技巧。除錯時,只有設定了斷點並使程式回到偵錯程式,才能對程式進行線上除錯。

設定斷點:可以通過下述方法設定一個斷點。首先把游標移動到需要設定斷點的程式碼行上,然後

  • 按F9快捷鍵
  • 彈出Breakpoints對話方塊,方法是按快捷鍵CTRL+B或ALT+F9,或者通過選單Edit/Breakpoints開啟。開啟後點擊Break at編輯框的右側的箭頭,選擇 合適的位置資訊。一般情況下,直接選擇line xxx就足夠了,如果想設定不是當前位置的斷點,可以選擇Advanced,然後填寫函式、行號和可執行檔案資訊。

去掉斷點:把游標移動到給定斷點所在的行,再次按F9就可以取消斷點。同前面所述,開啟Breakpoints對話方塊後,也可以按照介面提示去掉斷點。

條件斷點:可以為斷點設定一個條件,這樣的斷點稱為條件斷點。對於新加的斷點,可以單擊Conditions按鈕,為斷點設定一個表示式。當這個表示式發生改變時,程式就 被中斷。底下設定包括“觀察陣列或者結構的元素個數”,似乎可以設定一個指標所指向的記憶體區的大小,但是我設定一個比較的值但是改動 範圍之外的記憶體區似乎也導致斷點起效。最後一個設定可以讓程式先執行多少次然後才到達斷點。

資料斷點:資料斷點只能在Breakpoints對話方塊中設定。選擇“Data”頁,就顯示了設定資料斷點的對話方塊。在編輯框中輸入一個表示式,當這個 表示式的值發生變化時,資料斷點就到達。一般情況下,這個表示式應該由運算子和全域性變數構成,例如:在編輯框中輸入 g_bFlag這個全域性變數的名字,那麼當程式中有g_bFlag= !g_bFlag時,程式就將停在這個語句處。

訊息斷點:VC也支援對Windows訊息進行截獲。他有兩種方式進行截獲:視窗訊息處理函式和特定訊息中斷。
在Breakpoints對話方塊中選擇Messages頁,就可以設定訊息斷點。如果在上面那個對話方塊中寫入訊息處理函式的名字,那麼 每次訊息被這個函式處理,斷點就到達(我覺得如果採用普通斷點在這個函式中截獲,效果應該一樣)。如果在底下的下拉 列表框選擇一個訊息,則每次這種訊息到達,程式就中斷。

 值
Watch
VC支援檢視變數、表示式和記憶體的值。所有這些觀察都必須是在斷點中斷的情況下進行。
觀看變數的值最簡單,當斷點到達時,把游標移動到這個變數上,停留一會就可以看到變數的值。
VC提供一種被成為Watch的機制來觀看變數和表示式的值。在斷點狀態下,在變數上單擊右鍵,選擇Quick Watch, 就彈出一個對話方塊,顯示這個變數的值。
單擊Debug工具條上的Watch按鈕,就出現一個Watch檢視(Watch1,Watch2,Watch3,Watch4),在該檢視中輸入變數或者表示式,就可以觀察 變數或者表示式的值。注意:這個表示式不能有副作用,例如++運算子絕對禁止用於這個表示式中,因為這個運算子將修改變數的值,導致 軟體的邏輯被破壞。

Memory
由於指標指向的陣列,Watch只能顯示第一個元素的值。為了顯示陣列的後續內容,或者要顯示一片記憶體的內容,可以使用memory功能。在 Debug工具條上點memory按鈕,就彈出一個對話方塊,在其中輸入地址,就可以顯示該地址指向的記憶體的內容。

Varibles

Debug工具條上的Varibles按鈕彈出一個框,顯示所有當前執行上下文中可見的變數的值。特別是當前指令涉及的變數,以紅色顯示。

暫存器
Debug工具條上的Reigsters按鈕彈出一個框,顯示當前的所有暫存器的值。

 程序控制
VC允許被中斷的程式繼續執行、單步執行和執行到指定游標處,分別對應快捷鍵F5、F10/F11和CTRL+F10。各個快捷鍵功能如下: 
 

快捷鍵 說明
F5 繼續執行
F10 單步,如果涉及到子函式,不進入子函式內部
F11 單步,如果涉及到子函式,進入子函式內部
CTRL+F10 執行到當前游標處。

 Call Stack
呼叫堆疊反映了當前斷點處函式是被那些函式按照什麼順序呼叫的。單擊Debug工具條上的Call stack就顯示Call Stack對話方塊。在CallStack對話方塊中顯示了一個呼叫系列,最上面的是當前函式,往下依次是呼叫函式的上級函式。單擊這些函式名可以跳到對應的函式中去。

 其他除錯手段
系統提供一系列特殊的函式或者巨集來處理Debug版本相關的資訊,如下:

巨集名/函式名 說明
TRACE 使用方法和printf完全一致,他在output框中輸出除錯資訊
ASSERT 它接收一個表示式,如果這個表示式為TRUE,則無動作,否則中斷當前程式執行。對於系統中出現這個巨集 導致的中斷,應該認為你的函式呼叫未能滿足系統的呼叫此函式的前提條件。例如,對於一個還沒有建立的視窗呼叫SetWindowText等。
VERIFY 和ASSERT功能類似,所不同的是,在Release版本中,ASSERT不計算輸入的表示式的值,而VERIFY計算表示式的值。

 關注
一個好的程式設計師不應該把所有的判斷交給編譯器和偵錯程式,應該在程式中自己加以程式保護和錯誤定位,具體措施包括:

  • 對於所有有返回值的函式,都應該檢查返回值,除非你確信這個函式呼叫絕對不會出錯,或者不關心它是否出錯。
  • 一些函式返回錯誤,需要用其他函式獲得錯誤的具體資訊。例如accept返回INVALID_SOCKET表示accept失敗,為了查明 具體的失敗原因,應該立刻用WSAGetLastError獲得錯誤碼,並針對性的解決問題。
  • 有些函式通過異常機制丟擲錯誤,應該用TRY-CATCH語句來檢查錯誤
  • 程式設計師對於能處理的錯誤,應該自己在底層處理,對於不能處理的,應該報告給使用者讓他們決定怎麼處理。如果程式出了異常, 卻不對返回值和其他機制返回的錯誤資訊進行判斷,只能是加大了找錯誤的難度。

另外:VC中要編制程式不應該一開始就寫cpp/h檔案,而應該首先建立一個合適的工程。因為只有這樣,VC才能選擇合適的編譯、連線 選項。對於加入到工程中的cpp檔案,應該檢查是否在第一行顯式的包含stdafx.h標頭檔案,這是Microsoft Visual Studio為了加快編譯 速度而設定的預編譯標頭檔案。在這個#include "stdafx.h"行前面的所有程式碼將被忽略,所以其他標頭檔案應該在這一行後面被包含。
對於.c檔案,由於不能包含stdafx.h,因此可以通過Project settings把它的預編譯頭設定為“不使用”,方法是:

  • 彈出Project settings對話方塊
  • 選擇C/C++
  • Category選擇Precompilation Header
  • 選擇不使用預編譯頭。

 斷點
斷點是偵錯程式設定的一個程式碼位置。當程式執行到斷點時,程式中斷執行,回到偵錯程式。斷點是 最常用的技巧。除錯時,只有設定了斷點並使程式回到偵錯程式,才能對程式進行線上除錯。

設定斷點:可以通過下述方法設定一個斷點。首先把游標移動到需要設定斷點的程式碼行上,然後

  • 按F9快捷鍵
  • 彈出Breakpoints對話方塊,方法是按快捷鍵CTRL+B或ALT+F9,或者通過選單Edit/Breakpoints開啟。開啟後點擊Break at編輯框的右側的箭頭,選擇 合適的位置資訊。一般情況下,直接選擇line xxx就足夠了,如果想設定不是當前位置的斷點,可以選擇Advanced,然後填寫函式、行號和可執行檔案資訊。

去掉斷點:把游標移動到給定斷點所在的行,再次按F9就可以取消斷點。同前面所述,開啟Breakpoints對話方塊後,也可以按照介面提示去掉斷點。

條件斷點:可以為斷點設定一個條件,這樣的斷點稱為條件斷點。對於新加的斷點,可以單擊Conditions按鈕,為斷點設定一個表示式。當這個表示式發生改變時,程式就 被中斷。底下設定包括“觀察陣列或者結構的元素個數”,似乎可以設定一個指標所指向的記憶體區的大小,但是我設定一個比較的值但是改動 範圍之外的記憶體區似乎也導致斷點起效。最後一個設定可以讓程式先執行多少次然後才到達斷點。

資料斷點:資料斷點只能在Breakpoints對話方塊中設定。選擇“Data”頁,就顯示了設定資料斷點的對話方塊。在編輯框中輸入一個表示式,當這個 表示式的值發生變化時,資料斷點就到達。一般情況下,這個表示式應該由運算子和全域性變數構成,例如:在編輯框中輸入 g_bFlag這個全域性變數的名字,那麼當程式中有g_bFlag= !g_bFlag時,程式就將停在這個語句處。

訊息斷點:VC也支援對Windows訊息進行截獲。他有兩種方式進行截獲:視窗訊息處理函式和特定訊息中斷。
在Breakpoints對話方塊中選擇Messages頁,就可以設定訊息斷點。如果在上面那個對話方塊中寫入訊息處理函式的名字,那麼 每次訊息被這個函式處理,斷點就到達(我覺得如果採用普通斷點在這個函式中截獲,效果應該一樣)。如果在底下的下拉 列表框選擇一個訊息,則每次這種訊息到達,程式就中斷。

 值
Watch
VC支援檢視變數、表示式和記憶體的值。所有這些觀察都必須是在斷點中斷的情況下進行。
觀看變數的值最簡單,當斷點到達時,把游標移動到這個變數上,停留一會就可以看到變數的值。
VC提供一種被成為Watch的機制來觀看變數和表示式的值。在斷點狀態下,在變數上單擊右鍵,選擇Quick Watch, 就彈出一個對話方塊,顯示這個變數的值。
單擊Debug工具條上的Watch按鈕,就出現一個Watch檢視(Watch1,Watch2,Watch3,Watch4),在該檢視中輸入變數或者表示式,就可以觀察 變數或者表示式的值。注意:這個表示式不能有副作用,例如++運算子絕對禁止用於這個表示式中,因為這個運算子將修改變數的值,導致 軟體的邏輯被破壞。

Memory
由於指標指向的陣列,Watch只能顯示第一個元素的值。為了顯示陣列的後續內容,或者要顯示一片記憶體的內容,可以使用memory功能。在 Debug工具條上點memory按鈕,就彈出一個對話方塊,在其中輸入地址,就可以顯示該地址指向的記憶體的內容。

Varibles

Debug工具條上的Varibles按鈕彈出一個框,顯示所有當前執行上下文中可見的變數的值。特別是當前指令涉及的變數,以紅色顯示。

暫存器
Debug工具條上的Reigsters按鈕彈出一個框,顯示當前的所有暫存器的值。

 程序控制
VC允許被中斷的程式繼續執行、單步執行和執行到指定游標處,分別對應快捷鍵F5、F10/F11和CTRL+F10。各個快捷鍵功能如下: 
 

快捷鍵 說明
F5 繼續執行
F10 單步,如果涉及到子函式,不進入子函式內部
F11 單步,如果涉及到子函式,進入子函式內部
CTRL+F10 執行到當前游標處。

 Call Stack
呼叫堆疊反映了當前斷點處函式是被那些函式按照什麼順序呼叫的。單擊Debug工具條上的Call stack就顯示Call Stack對話方塊。在CallStack對話方塊中顯示了一個呼叫系列,最上面的是當前函式,往下依次是呼叫函式的上級函式。單擊這些函式名可以跳到對應的函式中去。

 其他除錯手段
系統提供一系列特殊的函式或者巨集來處理Debug版本相關的資訊,如下:

巨集名/函式名 說明
TRACE 使用方法和printf完全一致,他在output框中輸出除錯資訊
ASSERT 它接收一個表示式,如果這個表示式為TRUE,則無動作,否則中斷當前程式執行。對於系統中出現這個巨集 導致的中斷,應該認為你的函式呼叫未能滿足系統的呼叫此函式的前提條件。例如,對於一個還沒有建立的視窗呼叫SetWindowText等。
VERIFY 和ASSERT功能類似,所不同的是,在Release版本中,ASSERT不計算輸入的表示式的值,而VERIFY計算表示式的值。

 關注
一個好的程式設計師不應該把所有的判斷交給編譯器和偵錯程式,應該在程式中自己加以程式保護和錯誤定位,具體措施包括:

  • 對於所有有返回值的函式,都應該檢查返回值,除非你確信這個函式呼叫絕對不會出錯,或者不關心它是否出錯。
  • 一些函式返回錯誤,需要用其他函式獲得錯誤的具體資訊。例如accept返回INVALID_SOCKET表示accept失敗,為了查明 具體的失敗原因,應該立刻用WSAGetLastError獲得錯誤碼,並針對性的解決問題。
  • 有些函式通過異常機制丟擲錯誤,應該用TRY-CATCH語句來檢查錯誤
  • 程式設計師對於能處理的錯誤,應該自己在底層處理,對於不能處理的,應該報告給使用者讓他們決定怎麼處理。如果程式出了異常, 卻不對返回值和其他機制返回的錯誤資訊進行判斷,只能是加大了找錯誤的難度。

另外:VC中要編制程式不應該一開始就寫cpp/h檔案,而應該首先建立一個合適的工程。因為只有這樣,VC才能選擇合適的編譯、連線 選項。對於加入到工程中的cpp檔案,應該檢查是否在第一行顯式的包含stdafx.h標頭檔案,這是Microsoft Visual Studio為了加快編譯 速度而設定的預編譯標頭檔案。在這個#include "stdafx.h"行前面的所有程式碼將被忽略,所以其他標頭檔案應該在這一行後面被包含。
對於.c檔案,由於不能包含stdafx.h,因此可以通過Project settings把它的預編譯頭設定為“不使用”,方法是:

  • 彈出Project settings對話方塊
  • 選擇C/C++
  • Category選擇Precompilation Header
  • 選擇不使用預編譯頭。

2. 除錯輸出說明

在除錯程式的時候,我們可以使用下面這3個函式將除錯資訊輸出到控制檯視窗,這對我們除錯程式非常有幫助:

echo(text);
warn(text);
error(text);

其中echo函式用於輸出標準黑色字型的文字資訊到控制檯視窗中;warn函式用於輸出標準灰色字型的文字資訊到控制檯視窗中;error函式用於輸出標準紅色字型的文字資訊到控制檯視窗中。使用上述3個函式的時候,文字可根據字串規則進行格式化。

通過正確地使用恰當的輸出訊息,可以跟蹤在指令碼中發生的任何事件。一般情況下,人們都希望把最可能出現問題的地方的相關除錯資訊輸出到控制檯。您或許想將一個容易識別的標誌符置於程式碼某處,以便在控制檯的滾動視窗中找到它;或者輸出一些與程式碼相關的活動的重要資訊(這些資訊可能是一些變數的輸出)。

為了把控制檯輸出資訊轉儲在console.log檔案中,首先,您必須在您的程式碼中呼叫setLogMode函式,並確保該函式在程式執行至有問題的程式碼語句之前被執行。一個更為簡單的辦法就是:使用-log命令列選項,後接一個空格,然後輸入數字0、1或2。其中0表示您不能記錄日誌;1表示您可以把每一個新會話的內容追加到日誌檔案的末尾;2表示您可以用新日誌內容覆蓋以前的日誌檔案。

您可以用下面的方式在程式中設定標記:
error("******************************************");
它將在console . log檔案中新增一行星號:
******************************************;

在控制檯視窗中,這行星號會以紅色字元顯示,因此很容易識別。您也可以使用warn函式向控制檯視窗輸出灰色字元或使用echo函式向控制檯視窗輸出黑色字元。

很多時候,如果遊戲中出現停頓或者死鎖的情況,那麼,即使最後一行程式碼已經被執行,它的除錯輸出資訊也不會被寫到日誌檔案中。處理這種情況的方法很簡單:在程式中設定兩個一樣的錯誤行,一個緊接著位於另一個的右端。如果遊戲暫停,則只有第一行訊息輸出,那麼此時您就可以縮小錯誤查詢的範圍。接下來,把這兩個標記行往程式下方移動,直到它們不再出現在控制檯日誌中。這時,就可以找到出現問題的程式碼位置。

如果需要檢查一些重要變數的值,比如說X,Y和玩家的名稱,您可能會使用如下語句:

echo("player’s name: " @ playerName @ " X= " %X @ " Y=" @%Y );
然後,可以在控制檯視窗的日誌末尾看到這樣的輸出資訊:
player’s name: bozotheclown X=123  Y=456


3. 使用trace函式

Torque提供了一個很方便的跟蹤函式trace。使用它,在執行指令碼檔案時就可以計算出當前正在執行的是哪一行程式碼。當您苦苦思索一些邏輯問題的時候,這個功能尤為有效,您只需在感興趣的程式碼前面插入trace函式即可。使用trace(true)語句表示跟蹤的開始,在您關注的程式碼段末端插入trace(off)語句,禁用跟蹤功能。

您也可以通過開啟控制檯視窗,輸入:
trace(true);
來使跟蹤選項可用。

下面是控制檯視窗中的一段輸出(沒有使用trace函式)資訊

--------- Initializing MOD: Common ---------
Loading compiled script common/client/canvas.cs.
Loading compiled script common/client/audio.cs.
--------- Initializing MOD: Torque demo ---------
Loading compiled script demo/client/init.cs.
Loading compiled script demo/server/init.cs.
Loading compiled script demo/data/init.cs.
Loading compiled script demo/data/terrains/highplains/propertyMap.cs.

當使用trace函式後,輸出資訊就如下所示

--------- Parsing Arguments ---------
Entering [demo]parseArgs()
Entering [common]parseArgs()
Leaving [common]parseArgs() - return
Leaving [demo]parseArgs() - return
Entering [demo]onStart()
Entering [common]onStart()
--------- Initializing MOD: Common ---------
Entering initCommon()
Loading compiled script common/client/canvas.cs.
Loading compiled script common/client/audio.cs.
Leaving initCommon() - return
Leaving [common]onStart() – return
--------- Initializing MOD: Torque demo ---------
Loading compiled script demo/client/init.cs.
Loading compiled script demo/server/init.cs.
Loading compiled script demo/data/init.cs.
Loading compiled script demo/data/terrains/highplains/propertyMap.cs.
Entering initServer()

VC中的TRACE巨集:

  TRACE巨集對於VC下程式除錯來說是很有用的東西,有著類似printf的功能;該巨集僅僅在程式的DEBUG版本中出現,當RELEASE的時候該巨集就完全消失了,從而幫助你調式也在RELEASE的時候減少程式碼量。

  使用非常簡單,格式如下:

  TRACE("DDDDDDDDDDD");

  TRACE("wewe%d",333);

4. 在非MFC程式中使用除錯巨集ASSERT(),VERIFY()和 TRACE()

ASSERT()被測試它的引數,若引數為0,則中斷執行並列印一段說明訊息。在 Release 版本的程式中它不起任何作用。VERIFY()和 ASSERT()很相似,區別在於在 Release 版本中它仍然有效(譯者注:原作者在這裡沒有講清楚,VERIFY()不會列印說明,只是會對引數表示式求值)。ASSERT()使用的時候必須保證引數表示式中不能有函式呼叫(譯者注:ASSERT()巨集在 Release 版本中不對錶達式求值),因此對於任何有函式呼叫的引數表示式,應該使用巨集 VERIFY(),以保證表示式中的函式呼叫在 Release 版本中會被正確求值。TRACE()基本上就是函式 printf()的一個複製品,唯一的區別是它把結果輸出到除錯視窗。在 Release 版本中,它也是無效的。這三個巨集在 Release 版本中都不會產生任何實質性的影響,它們是否起作用取決於是否定義了預定義了巨集 _DEBUG。這是對 Microsoft Visual C++ 而言,在其它的編譯器中可能其它不同的巨集。

  Since it makes no sense to re-invent the wheel(譯者注:這好像是一句俗語,大致意思是“沒有必要(意義)自己從頭寫起”,但原句究竟如何,在下水平有限,實難猜出。故將原文放上,望高人賜教,感激不盡!),筆者在看了 MFC 的程式碼之後類似地建立了自己的巨集。對於 ASSERT()和 VERIFY()則去掉了花哨的“Debug assertion failed...”對話方塊,只是簡單的產生一個單純的斷點中斷。

  要使用 ASSERT(),VERIFY()和 TRACE(),有兩個檔案是必需的:debug.h 和 debug.cpp。首先需要在工程中的主要標頭檔案裡中包含檔案 debug.h。因為它本身沒有包括其它任何標頭檔案,所以不必擔心會產生頭件的包含遞迴。另外還要將debug.cpp 加入到工程中的原始檔中。

這裡是程式碼:

<span style="font-family: Fixedsys;"><span style="color: rgb(113, 113, 113);">// file debug.h</span>
#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}}  <span style="color: rgb(113, 113, 113);">// 譯註:為除錯版本時產生中斷有效</span>

#else
#define ASSERT(x)
#define VERIFY(x) x                  <span style="color: rgb(113, 113, 113);">// 譯註:為發行版本時不產生中斷</span>
#endif

#ifdef _DEBUG
#define TRACE _trace

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

#endif <span style="color: rgb(113, 113, 113);">// __DEBUG_H__</span>


<span style="color: rgb(113, 113, 113);">// file debug.cpp</span>
#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);     <span style="color: rgb(113, 113, 113);">// 譯註:格式化輸入的字串 fmtt</span>
	va_end(body);                 <span style="color: rgb(113, 113, 113);">//       到輸出字串 ou</span>
	OutputDebugString(out);       <span style="color: rgb(113, 113, 113);">// 譯註:輸出格式化後的字串到偵錯程式</span>
}
#endif</span><span style="font-family: Tahoma;">
</span>

譯者續:一點小擴充套件

  大家可以看到巨集 TRACE()的最後,呼叫的是 OutPutDebugString()函式,只能將資訊輸出到偵錯程式視窗中,但我們同樣也可以實現 MFC 中的彈出式視窗,只要用 MessageBox()函式輸出就可以了。(不過……好像樣子也不一樣哎!)

相關推薦

VS除錯以及Trace函式用法

. VC除錯入門 設定 為了除錯一個程式,首先必須使程式中包含除錯資訊。一般情況下,一個從AppWizard建立的工程中包含的Debug Configuration自動包含除錯資訊,但是是不是Debug版本並不是程式包含除錯資訊的決定因素,程式設計者可以在任意的Conf

srand()以及rand()函式用法

srand()就是給rand()提供種子seed 如果srand每次輸入的數值是一樣的,那麼每次執行產生的隨機數也是一樣的, srand(n) for(10) rand()也就是說,以一個固定的數值作為種子是一個缺點。 通常的做法是  以這樣一句程式碼

srand()以及rand()函式用法(zz)

  srand()就是給rand()提供種子seed 如果srand每次輸入的數值是一樣的,那麼每次執行產生的隨機數也是一樣的, srand(n) for(10) rand()也就是說,以一個固定的數值作為種子是一個缺點。 通常的做法是  以這樣一句程式碼srand((u

Hive 中的複合資料結構簡介以及一些函式用法說明

目錄[-] 一、map、struct、array 這3種的用法: 1、Array的使用 2、Map 的使用 3、Struct 的使用 4、資料組合 (不支援組合的複雜資料型別) 二、hive中的一些不常見函式的用法: 1、array_contains (

自己定義一個加減乘除函式以及lambda函式用法

使用lambda函式實現一個加減乘除函式的定義 def calc(num_list, fn): result = num_list[0] for index in range(1, len(num_list)): resul

matlab中dir函式以及sort函式用法

dir函式的作用:返回當前路徑中的所有檔案以及資料夾所組成的列表。 dir %returns a list of files and folders in the current folder.類似於Dos命令中的DIR dir name  (或者 dir(name))

matlab曲線擬合 函式 用法以及例子

資料準備: 關於MATLAB曲線擬合,我寫了一系列的經驗,為了相互統一,採用下面的資料: x=[0    0.3000    0.6000    0.9000    1.2000    1.5000    1.8000    2.1000    2.4000    2.7000    3.0000]

C語言—理解函式指標以及它的用法

什麼是函式指標? 指標前面已經寫過好多,自以為認識的差不多了,但是今天突然看到一個問題,寫一個函式指針,函式指標就是一個指向函式首地 址的指標,接下來寫幾個指標: 寫一個函式指標 寫一個函

Mysql函式以及date函式的一些操作及用法

    對於mysql和ms sql中提供了大量的對時間處理的函式;因為在實際的查詢操作中很多地方都存在對時間格式話的操作處理,所以這裡就拿mysql來說下如何去處理這些時間   mysql 部分date函式的使用:    

【OpenCV】查詢表用法以及LUT函式的使用

參考的三篇部落格的地址 簡單地說,查詢表就是通過建立一個table與源影象之間建立一個對映,可以使單通道,也可以是多通道,在定義將0~255的畫素對映成為不同的值後,通過查詢表的下標進行相應的賦值操作,例如table[127]=0 表示的就是將源影象中灰度值為1

matlab max/min/median函式用法以及自定義函式求最大最小值和中位數

宣告:筆者關於matlab主題的帖子內容均來自於課堂作業,課堂筆記以及自己在學習過程中查詢matlab官方文件獲得的學習經驗,分享到CSDN一方面是作為自己的學習筆記,另一方面希望可以幫助到和我一樣

報表版本的資料選擇對應section的規則以及N函式除錯方法

1如果有非條件section綁定了檢視那麼版本的資料選擇對應的是第一個繫結檢視的非條件section 否則版本的資料選擇對應的是第一個繫結檢視的條件section或者沒有對應 2除錯N函式可以用地球+

VS開發】recv函式函式返回值說明(特別有利於工程除錯

當返回值是0時,為正常關閉連線; windows版本: 第四個引數: MSG_PEEK 檢視當前資料。資料將被複制到緩衝區中,但並不從輸入佇列中刪除。 MSG_OOB 處理帶外資料(參見2.2.3節具體討論)。 返回值: 若無錯誤發生,recv()返回讀入的位元組數。如果連線已中止,返回0。否則的

ffmpeg中av_image_alloc()函式用法 以及 另一種同樣功能的函式用法

一、ffmpeg中av_image_alloc()是這樣定義的。此函式的功能是按照指定的寬、高、畫素格式來分析影象記憶體。引數說明: pointers[4]:儲存影象通道的地址。如果是RGB,則前三個指標分別指向R,G,B的記憶體地址。第四個指標保留不用 linesi

除錯】列印函式棧,以及函式指標輸出函式名的方法

Before All 以下皆在linux環境下。windows上用vs可隨時檢視函式棧。 使用者態 列印函式棧 使用backtrace()相關函式來達到輸出函式棧的目的,man backtrace檢視詳細的引數,返回值等資訊。 以下測試例,編譯

呼叫自己生成的動態連結庫(DLL) VS除錯(debug)右鍵無法進入函式定義

問題描述: 自己建立的動態連結庫工程,編譯後生成的DLL檔案。在另一個VS工程中使用DLL中的函式,在除錯的時候發現右鍵無法跳轉到函式定義位置(兩個工程檔案在同一裝置上)。 問題分析: 無法跳轉說明該函式無法定位到原始檔的位置,這是因為在動態連結庫工程中沒有配置生成除錯

Python中可迭代物件、迭代器以及iter()函式的兩個用法詳解

在Python中,有這兩個概念容易讓人混淆。第一個是可迭代物件(Iterable),第二個是迭代器(Iterator),第三個是生成器(Generator),這裡暫且不談生成器。 可迭代物件 列表、元組、字串、字典等都是可迭代物件,可以使用for迴圈遍歷出所有元素的都可以稱為可迭代物件(Iterable)。在

$.each()和$().each(),以及forEach()的用法

數組 轉載 指正 var asc body $() func www 1.forEach是js中遍歷數組的方法,如下 var arr=[1,2,3,4];arr.forEach(function(val,index,arr){//val為數組中當前的值,index為當前值

JFileChooser和FileFilter的使用,以及Java RandomAccessFile用法

選擇 沒有 定義 相關 lte inpu 概念 獨立 文件 今天學習前輩的一個p2p下載的源代碼,其中遇見了兩個小問題,上網進行了百度,找到了答案,隨手記錄一下,以便於以後翻看。 1.首先自定義了一個文件下載的主界面,包括了創建任務、暫停任務、繼續任務、刪除任務,點擊創建任

dos中定義變量與獲取常見的引用變量以及四則運算(set用法)

邏輯或 dos 擴展 use mysql\ gpo 當前 直接 var 在dos中使用set定義變量: set a=8 (註意等號兩邊沒有空格) 引用變量如: echo %a% 將打印a的值  (%a%是獲取變量a的值)