VS2008調試技巧收集備用
VS2005調試技巧集合
http://blog.csdn.net/rainylin/archive/2007/09/06/1775125.aspx
下面有從淺入深的6個問題,您可以嘗試回答一下
- 一個如下的語句for (int i = 0; i < 10; i++){if (i == 5)j = 5;},什么都寫在一行,你怎么在j=5前面插入斷點
- 在一個1000次的循環體內部設置斷點,你希望當循環進行到900次后中斷,怎么才能做到呢?
- 你有一個表達式在上面循環的某一次發生了變化,你想知道是哪一次,在哪個地方,怎么才能做到?
- 你希望你的斷點在被命中100次后,每命中三次中斷一次,比如第103,第106,第109怎樣做?
- 你有在調試一個服務程序,希望在其內部打上了斷點,可是,由于這是一個公用的服務你不希望其他訪問這個服務的程序被你的調試所干擾,你想 怎么辦?
- 怎樣知道2個斷點中斷的時間間隔
問題1,2
- 一個如下的語句for (int i = 0; i < 10; i++){if (i == 5)j = 5;},什么都寫在一行,你怎么在j=5前面插入斷點
- 在一個1000次的循環體內部設置斷點,你希望當循環進行到900次后中斷,怎么才能做到呢?
這兩個問題最簡單,我在一個例子里說明
例如如下循環
for(int i=0;i<1000;i++){doSomeThing......}
在循環的大括號上單擊右鍵,插入斷點,用這個方法,可以對付那些喜歡把語句寫在一行上的家 伙,其實,隨著.Net3.5中Linq的出現,我們肯定也會經常在在一行上寫復雜的表達式,這個時候用這種插入方法會比較管用
ok,現在我們來編輯這個斷點的條件,在斷點上右鍵單擊,選擇如圖菜單項
在彈出的窗口中可以設置斷點命中的條件i==900
注意我是在調試C#代碼,默認的條件語句語法是C#,如果你想切換,那就需要用Ctrl- B,來插入斷點,并在彈出窗口中選擇語言
通過這樣設置條件斷點,我們就可以解決我們的問題1,2了
問題3
你有一個表達式在上面循環的某一次發生了變化,你想知道是哪一次,在哪個地方,怎么才能做到?
同樣通過設置條件斷點我們還可以解決我們的問題3,對表達式變化的跟蹤
string user="yizhu2000"
for(int i=0;i<10000;i++){
DoSomething1()
.......
DoSomethingN()
}
當循環執行完畢時我們發現user變成了"smart_boy",你不知道這個值是在第幾次 循環的時候變化的,那么你是不是會選擇打上斷點,一次一次中斷,來查看呢?當然不用
在循環體結束的位置我們設置一個斷點,打開條件編輯窗口(打開方法同上),設置表達式為 user,勾選下面的HasChanged,也就是說,你告訴斷點,當user的值發生變化時才觸發
(注意:第一次執行到斷點的時候,程序一定會中斷,并計算這時表達式的值,所以,所謂發生變 化,指的是以后執行到斷點是表達式的值和第一次執行到斷點時表達式的值的比較)
問題4
你希望你的斷點在被命中100次后,每命中三次中斷一次,比如第103,第106,第109怎樣做?
如何讓斷點在指定的命中次數或者大于某個次數時觸發呢?方法是設定幾個斷點的 HitCount,右鍵單擊斷點,在彈出菜單中選擇Hit Count,會彈出如下窗口
在"when the break point is hit"下拉列表里,我們可以看到四個選項
break always:總是中斷
break when the hit count is equal to:等于某次數時中斷
beak when the hit count is a multpile of:當次數是某數的倍數時中斷
break when the hit count is greater than or equal to:當大于等于某數時中斷
問題5
你有在調試一個服務程序,希望在其內部打上了斷點,可是,由于這是一個公用的服務你不希望其他訪問這個服務的程序被你的調試所干擾,你想 怎么辦?
前面4個問題都已經解決了,第5個問題的解決方法是利用斷點的Filter功能,比如我希望 斷點只有被機器名為yizhu的機器訪問才能觸發,我可以這樣設置
當其他機器訪問程序的時候,斷點將不會觸發,這樣做的優點是通過設置機器名,我們可以讓其他 機器訪問的時候感覺不到斷點的存在,除此之外我們可以設 置機器名,進程號,進程名,線程號,線程名作為filter,而且還可以把他們組合起來,比如我希望通過當機器yizhu的dllhost進程調用時才觸 發,那么問題就可以設置為MachineName="yizhu"&ProcessName="dllhost"
問題6 怎樣知道2個斷點中斷的時間間隔
現在我們來解決第6個問題:
在程序性能調試的時候,我們經常需要知道某段代碼的執行效率,一般來說,我們可以在程序中加 入時間點,通過時間點相減來取得時間間隔,這種方法有個 顯而易見的缺點就是需要修改程序,想要不修改程序,就需要借助一些工具,那么有沒有什么方法可以聲明式的插入時間點,并計算值呢?其實斷點完全可以做到
在給出方法前,我們來看看斷點的另外一個設置項,When Hit,這個選項可以讓我們在命中斷點后做一些事情,包括輸出一 些內容,或者調用宏,比如輸出一個程序中變量的值
我們輸出了變量user的值,下面Continue Execution表示程序不會中斷,輸出后繼續執行,注意表達式需要用{}括起來,,其他的部分會被作為字符串輸出。設定WhenHit后斷點變成了方 形(看厭了圓斷點,我還挺喜歡這個方家伙的)
在output中查看輸出結果,如下:
既然可以計算表達式,我們的第一個最簡方案就出來了,也就是在程序執行到斷點的時候,輸出 DateTime.Now,這樣當然是可行的,但是我們需 要的是時間間隔,所以我們還需要自己來算個減法,還是挺麻煩的,怎么樣才能讓程序自己輸出時間間隔呢?有一個想法是這樣的,我們在上一個斷點聲明一個時間 變量,然后在下面的斷點里用DataTime.Now減去這個變量,即
斷點一的條件:{DateTime _t=DateTime.Now;}
斷點二的條件:{DateTime.Now-t;}
看起來不錯,但是實際運行時就有問題了,讓我們看看輸出吧
上面高亮的部分說,變量申明只能在immediate window中進行,所以斷點一的變量沒有申明成功,關于immediatewindow,我們以后會涉獵到,反正就是說想在表達式里申明變量,沒門,死 路一條.那么我們怎么才能不申明變量又時間點呢?
這時我想起了Thread.SetData 方法,這個方法可以往當前線程專門提供的空間中插入一些數據,并且可以通過GetData得到數據,具體細節參考
http://msdn2.microsoft.com/zh-cn/library/system.threading.thread.setdata(VS.80).aspx
于是方案就有了,在第一個斷點處把時間放入Thread的DataSlot,然后第二個斷點 取出來相減
斷點一的條件: {Thread.SetData(Thread.GetNamedDataSlot("ExecutionTime"),DateTime.Now);}
斷點二的條件: {DateTime.Now-(DateTime)System.Threading.Thread.GetData(System.Threading.Thread.GetNamedDataSlot("ExecutionTime"));}
看看輸出效果
我們的目的已經達到了,output中成功的輸出了時間間隔,當然,還不是很完善,首先,這 個方法限于兩個斷點,你想多打幾個斷點,測試兩兩間的間隔還是比較麻煩.測量精度也可以提高,大家有興趣可以自己研究這個方法的擴展
==================================
《高效編程十八式》(11/13)調試
http://blog.sina.com.cn/s/blog_4ed027020100hgr6.html調試
王偉冰
調試可以深入程序內部,觀察運行時各個變量的值。但是,并不是一出現bug就要調試。調試最適合用來探究一些自己不太熟悉的語言特性或者是技術。比如你對 C++某些語句的作用不太熟悉,對某個庫函數的作用不太熟悉,調試一下,就可以看得清清楚楚了。如果程序只是邏輯出錯誤,最好的方法是測試,通過逐個單元 的測試,找出問題的所在。為什么測試的效率更高?因為測試可以是自動化的,你可以編寫測試代碼,一次性地完成很多測試,但調試只能一步一步地來。調試的好 處是可以直接看變量的值,而測試的話,必須寫額外的代碼把變量的值輸出到控制臺或者日志文件里。下面說一些調試的技巧。
斷點
最簡單的一種,設置一個斷點,程序執行到那一句就自動中斷進入調試狀態。
單步執行
有三種,一種是每次執行一行;一種是每次執行一行,但遇到函數調用就會跳到被調用的函數里;一種是直接執行當前函數里剩下的指令,返回上一級函數。在 Visual Studio中,上面三種方法對應的快捷鍵分別為F10、F11、Shift+F11。
監視
調試器可能會自動列出一些相關變量的值,但是你可能還關心其它變量的值,可以添加對這些變量的監視。還可以監視一個表達式的值,比如a+b。但是,這個表 達式最好不要修改變量的值,比如監視a++都會導致監視時修改了a的值,影響了程序的運行結果。
條件中斷
假如你有這樣的循環:
for(int i=0;i<100;i++){
for(int j=0;j<100;j++){
……
}
}
你懷疑當i=10且j=10的時候執行有問題,那如何調試?用斷點的話,從i=0的初始狀態,需要中斷10次才能到i=10,然后從j=0也需要再中斷 10次,才能到j=10的狀態。所以想進入i=10且j=10的狀態,需要中斷20次,這太麻煩了。可以使用條件中斷:
for(int i=0;i<100;i++){
for(int j=0;j<100;j++){
if(i==10 && j==10){
; //空語句
}
……
}
}
在空語句的那一行設置斷點就可以了。
上面的if結構太占地方,還可以用assert:
assert(i!=10 || j!=10);
斷言i不為10或j不為10,那么當i=10且j=10的時候,斷言就不成立,程序就會中斷,進入調試狀態。
有時候用throw也可以中斷:
if(i==10 && j==10)throw;
但是最好不要這樣做,調試器不一定會在throw的地方中斷。
控制變量法
其實這已經不算是調試的內容了,但是也是一種找出bug原因的手段,所以還是在這里說。
控制變量法常用于科學研究中,比如說,研究牛頓第二定律a=F/m,a與F和m都有關,那么可以先固定m,研究a與F的關系;然后固定F,研究m與a的關 系。
對于一個程序來說,一個bug可能跟多處代碼有關。假如你懷疑這個bug與某些語句有關,可以把這些語句注釋掉,或者是改一改,看看bug是否還存在,如 果不存在,說明確實跟這些語句有關。(當然,要保證程序少了這些語句之后還可以順利運行。)如果bug還存在,就說明它跟這些語句無關。
有些時候我們缺乏調試工具,比如在網頁上運行的程序,在特殊設備上運行的程序,那么控制變量法是一種很有用的代替手段。
二分法
二分法是控制變量法的進一步擴展。
在數學上,二分法用于求一個連續函數的根。比如一個函數f(x),如果f(x1)>0且f(x2)<0, 那么在區間x1和x2之間,必定存在一個x,使f(x)=0。然后我們再考察區間的中點x3=(x1+x2)/2, 如果f(x3)>0,則函數的根就在區間x3和x2之間,如果f(x3)<0, 那么函數的根就在區間x1和x3之間。如此不斷地把區間一分為二,最后鎖定函數的根。
對于一個程序來說,如果當前情況是有bug的,那就好比是f(x1)>0;如果你把main函數里所有的操作都注釋掉,那么 程序什么都不做,就不可能有bug,那就好比是f(x2)<0;于是在這兩種狀態之中,肯定存在一些臨界的語句,當這些語句 改動的時候,就會使程序在有bug和無bug狀態間切換,這些語句就是bug的原因所在。運用二分法的思想可以鎖定這些臨界語句。一開始先對程序做一些大 刀闊斧的改動,比如說,程序的主循環會循環10次,就改成1次;程序有10個功能,就關掉5個功能。看看哪些改動,可以讓程序由有bug狀態切換到無 bug狀態。找到這樣改動后,就把這個改動再細分成幾個小改動,比如關掉5個功能,就細分為關掉一兩個功能,再看看哪些小改動可以讓程序由有bug狀態切 換到無bug狀態。如此一步一步縮小包圍圈,就后鎖定一個無法再分的小改動,這個改動就是bug的原因所在。
同步法
有些bug是由于多線程而產生的。因為在不同線程里的操作我們無法預測其發生的順序,可能當它們按某種次序進行時,bug不會出現,當它們按另一種次序進 行時,bug就出現了。比如多線程那一節說到的那個銀行帳戶,如果沒有加同步鎖,就會出現這種bug。對這種bug的調試是很困難的,有時你運行程序發現 了bug,而在進行調試的時候,由于執行順序不同了,bug又不出現了。
為了解決這個問題,我想了一個辦法,就是利用同步事件,強行把多線程的程序按照預定好的順序去執行。比如說有兩個線程,一開始就讓線程1運行,線程2睡 覺,線程1運行到某個特定的點后,就換線程2運行,線程1睡覺。任何時候,都只有一個線程可以運行。我們可以在多次運行的過程中使用不同的執行順序,如果 按某種執行順序運行之后bug浮現了,那么就把這種順序記錄下來。然后按照這種順序進入調試,找出bug。
用這種方法一定要謹慎,如果你的程序里本來就有線程同步的代碼,再加上這些強制的同步,可以會導致死鎖。
=============================================
Visual Studio 調試(Debug)小技巧
http://hi.baidu.com/liudong/blog/item/d0434c08c6d315970b7b827e.html
在Visual Studio 運行調試過程中,有兩個非常有用的小工具:
1,Command Window。
2,Immediate Window。
Command Window用于執行一些有用的命令。例如創建一個新文件可以使用命令:
File.NewFile "abc.cpp"
有趣的是提供一個和Dos中cls類似命令。
Immediate Window提供在調試過程中運行一些有用的表達式,或者查看程序中的變量的值。例如程序中有兩個變量a和b,現在要測試a+b的值,可以使用下面的命令 (注意前面的>不可省略):
>Debug.Print a + b
MSDN參考:
ms-help://MS.MSDNQTR.v90.en/dv_vscmds/html/48711628-1909-4713-a73e-d7b714c77f8a.htm
ms-help://MS.MSDNQTR.v90.en/dv_vscmds/html/d33e7937-73f3-4c69-9df0-777a8713c6f2.htm
====================================
在vs2008 C++下調試控制臺程序的 心得及技巧
http://blog.sina.com.cn/s/blog_62466e480100f8cw.htmlVisual Studio 2008環境與VC6.0的環境存在著比較大的區別,下面就一些小小的區別在這里做一些探討,歡迎指教!
1、如果是調試控制臺程序,很多時候點擊“啟動調試”后是一閃而過,此時可有兩種方法讓cmd下dos調試屏幕暫停:
A:不要直接點擊vs2008的“啟動調試”按鈕,而是按Control+F5組合鍵。
B:在主函數main()里“return 0;”前加上兩句:cin.get();樣式如下
eg: int main()
{
cout<<"這是一個調試屏幕暫停的例子!"<<endl;
cin.get();
cin.get();
return 0;
}
2、類、函數和變量是C++編譯器的標準組件,它們都放置在名稱空間std中(此時頭文件沒有后綴名h)。在vs2008 C++下,如果不包含using namespace std;指令,那么必須使用std::前綴,如
#include "stdafx.h"
#include<iostream> //頭文件沒有h后綴名
void simon(int); //函數原型
//using namespace std; 沒有使用std名稱空間
int _tmain(int argc, _TCHAR* argv[])
{
simon(3);
std::cout<<"請輸入一個整數: "; //必須使用std::前綴,以下都是
int count;
std::cin>>count;
simon(count);
std::cout<<"完成!"<<std::endl;
std::cin.get();//這兩行是使調試屏幕暫停,不會一閃而過
std::cin.get();//讓程序等待鍵擊
return 0;//退出主函數
}
void simon(int n) //自定義函數
{
std::cout<<"現在整數是 "<<n<<"測試!"<<std::endl;
}
下面是一個使用using namespace std;名稱空間的對比:
#include "stdafx.h"
#include<iostream>
void simon(int);
using namespace std; //這是一個使用std;名稱空間的例子
int _tmain(int argc, _TCHAR* argv[])
{
simon(3);
cout<<"請輸入一個整數: ";
int count;
cin>>count;
simon(count);
cout<<"完成!"<<endl;
cin.get();
cin.get();
return 0;
}
void simon(int n)
{
cout<<"現在整數是: "<<n<<" 測試!"<<endl;
}
還有一種方法,就是既不使用std;名稱空間,也不使用std::前綴,而是使用using編譯指令。如:
#include "stdafx.h"
#include<iostream>
using std::cout; //直接使用using指令
using std::cin;
using std::endl;
void simon(int);
//using namespace std; //這是一個既沒有使用std;名稱空間也沒有使用std::前綴的例子
int _tmain(int argc, _TCHAR* argv[])
{
simon(3);
cout<<"請輸入一個整數: ";
int count;
cin>>count;
simon(count);
cout<<"完成!"<<endl;
cin.get();
cin.get();
return 0;
}
void simon(int n)
{
cout<<"現在整數是: "<<n<<" 測試!"<<endl;
}
===========================
RFID管理系統集成商 RFID中間件 條碼系統中間層 物聯網軟件集成