青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

牽著老婆滿街逛

嚴以律己,寬以待人. 三思而后行.
GMail/GTalk: yanglinbo#google.com;
MSN/Email: tx7do#yahoo.com.cn;
QQ: 3 0 3 3 9 6 9 2 0 .

調試技巧之調用堆棧

簡單介紹

調試是程序開發者必備技巧。如果不會調試,自己寫的程序一旦出問題,往往無從下手。本人總結10年使用VC經驗,對調試技巧做一個粗淺的介紹。希望對大家有所幫助。

今天簡單的介紹介紹調用堆棧。調用堆棧在我的專欄的文章VC調試入門提了一下,但是沒有詳細介紹。

首先介紹一下什么叫調用堆棧:假設我們有幾個函數,分別是function1,function2,function3,funtion4,且function1調用function2,function2調用function3,function3調用function4。在function4運行過程中,我們可以從線程當前堆棧中了解到調用他的那幾個函數分別是誰。把函數的順序關系看,function4、function3、function2、function1呈現出一種“堆棧”的特征,最后被調用的函數出現在最上方。因此稱呼這種關系為調用堆棧(call stack)。

當故障發生時,如果程序被中斷,我們基本上只可以看到最后出錯的函數。利用call stack,我們可以知道當出錯函數被誰調用的時候出錯。這樣一層層的看上去,有時可以猜測出錯誤的原因。常見的這種中斷時ASSERT宏導致的中斷。

在程序被中斷時,debug工具條的右側倒數第二個按鈕一般是call stack按鈕,這個按鈕被按下后,你就可以看到當前的調用堆棧。

實例一:介紹

我們首先演示一下調用堆棧。首先我們創建一個名為Debug的對話框工程。工程創建好以后,雙擊OK按鈕創建消息映射函數,并添加如下代碼:

void CDebugDlg::OnOK() 
{ 
// TODO: Add extra validation here ASSERT(FALSE);
}

我們按F5開始調試程序。程序運行后,點擊OK按鈕,程序就會被中斷。這時查看call stack窗口,就會發現內容如下:

CDebugDlg::OnOK() line 176 + 34 bytes
_AfxDispatchCmdMsg(CCmdTarget * 0x0012fe74 {CDebugDlg}, unsigned int 1, int 0, void (void)* 0x5f402a00 `vcall'(void), void * 0x00000000, unsigned int 12, AFX_CMDHANDLERINFO * 0x00000000) line 88
CCmdTarget::OnCmdMsg(unsigned int 1, int 0, void * 0x00000000, AFX_CMDHANDLERINFO * 0x00000000) line 302 + 39 bytes
CDialog::OnCmdMsg(unsigned int 1, int 0, void * 0x00000000, AFX_CMDHANDLERINFO * 0x00000000) line 97 + 24 bytes
CWnd::OnCommand(unsigned int 1, long 656988) line 2088
CWnd::OnWndMsg(unsigned int 273, unsigned int 1, long 656988, long * 0x0012f83c) line 1597 + 28 bytes
CWnd::WindowProc(unsigned int 273, unsigned int 1, long 656988) line 1585 + 30 bytes
AfxCallWndProc(CWnd * 0x0012fe74 {CDebugDlg hWnd=???}, HWND__ * 0x001204b0, unsigned int 273, unsigned int 1, long 656988) line 215 + 26 bytes
AfxWndProc(HWND__ * 0x001204b0, unsigned int 273, unsigned int 1, long 656988) line 368
AfxWndProcBase(HWND__ * 0x001204b0, unsigned int 273, unsigned int 1, long 656988) line 220 + 21 bytes
USER32! 77d48709()
USER32! 77d487eb()
USER32! 77d4b368()
USER32! 77d4b3b4()
NTDLL! 7c90eae3()
USER32! 77d4b7ab()
USER32! 77d7fc9d()
USER32! 77d76530()
USER32! 77d58386()
USER32! 77d5887a()
USER32! 77d48709()
USER32! 77d487eb()
USER32! 77d489a5()
USER32! 77d489e8()
USER32! 77d6e819()
USER32! 77d65ce2()
CWnd::IsDialogMessageA(tagMSG * 0x004167d8 {msg=0x00000202 wp=0x00000000 lp=0x000f001c}) line 182
CWnd::PreTranslateInput(tagMSG * 0x004167d8 {msg=0x00000202 wp=0x00000000 lp=0x000f001c}) line 3424
CDialog::PreTranslateMessage(tagMSG * 0x004167d8 {msg=0x00000202 wp=0x00000000 lp=0x000f001c}) line 92
CWnd::WalkPreTranslateTree(HWND__ * 0x001204b0, tagMSG * 0x004167d8 {msg=0x00000202 wp=0x00000000 lp=0x000f001c}) line 2667 + 18 bytes
CWinThread::PreTranslateMessage(tagMSG * 0x004167d8 {msg=0x00000202 wp=0x00000000 lp=0x000f001c}) line 665 + 18 bytes
CWinThread::PumpMessage() line 841 + 30 bytes
CWnd::RunModalLoop(unsigned long 4) line 3478 + 19 bytes
CDialog::DoModal() line 536 + 12 bytes
CDebugApp::InitInstance() line 59 + 8 bytes
AfxWinMain(HINSTANCE__ * 0x00400000, HINSTANCE__ * 0x00000000, char * 0x00141f00, int 1) line 39 + 11 bytes
WinMain(HINSTANCE__ * 0x00400000, HINSTANCE__ * 0x00000000, char * 0x00141f00, int 1) line 30
WinMainCRTStartup() line 330 + 54 bytes
KERNEL32! 7c816d4f()

這里,CDebugDialog::OnOK作為整個調用鏈中最后被調用的函數出現在call stack的最上方,而內核中程序的啟動函數Kernel32! 7c816d4f()則作為棧底出現在最下方。

實例二:學習處理方法

微軟提供了MDI/SDI模型提供文檔處理的建議結構。有些時候,大家希望控制某個環節。例如,我們希望彈出自己的打開文件對話框,但是并不想自己實現整個文檔的打開過程,而更愿意MFC完成其他部分的工作。可是,我們并不清楚MFC是怎么處理文檔的,也不清楚如何插入自定義代碼。

幸運的是,我們知道當一個文檔被打開以后,系統會調用CDocument派生類的Serialize函數,我們可以利用這一點來跟蹤MFC的處理過程。

我們首先創建一個缺省的SDI工程Test1,并在CTest1Doc::Serialize函數的開頭增加一個斷點,運行程序,并打開一個文件。這時,我們可以看到調用堆棧是(我只截取了感興趣的一段):

CTest1Doc::Serialize(CArchive & {...}) line 66
CDocument::OnOpenDocument(const char * 0x0012f54c) line 714
CSingleDocTemplate::OpenDocumentFile(const char * 0x0012f54c, int 1) line 168 + 15 bytes
CDocManager::OpenDocumentFile(const char * 0x0042241c) line 953
CWinApp::OpenDocumentFile(const char * 0x0042241c) line 93
CDocManager::OnFileOpen() line 841
CWinApp::OnFileOpen() line 37
_AfxDispatchCmdMsg(CCmdTarget * 0x004177f0 class CTest1App  theApp, unsigned int 57601, int 0, void (void)* 0x00402898 CWinApp::OnFileOpen, void * 0x00000000, unsigned int 12, AFX_CMDHANDLERINFO * 0x00000000) line 88
CCmdTarget::OnCmdMsg(unsigned int 57601, int 0, void * 0x00000000, AFX_CMDHANDLERINFO * 0x00000000) line 302 + 39 bytes
CFrameWnd::OnCmdMsg(unsigned int 57601, int 0, void * 0x00000000, AFX_CMDHANDLERINFO * 0x00000000) line 899 + 33 bytes
CWnd::OnCommand(unsigned int 57601, long 132158) line 2088
CFrameWnd::OnCommand(unsigned int 57601, long 132158) line 317

從上面的調用堆棧看,這個過程由一個WM_COMMAND消息觸發(因為我們用菜單打開文件),由CWinApp::OnFileOpen最先開始實際處理過程,這個函數調用CDocManager::OnFileOpen打開文檔。

我們首先雙擊CWinApp::OnFileOpen() line 37打開CWinApp::OnFileOpen,它的處理過程是:

    ASSERT(m_pDocManager != NULL);
    m_pDocManager->OnFileOpen();

m_pDocManager是一個CDocManager類的實例指針,我們雙擊CDocManager::OnFileOpen行,看該函數的實現:

void CDocManager::OnFileOpen()
{
 // prompt the user (with all document templates)
 CString newName;
 if (!DoPromptFileName(newName, AFX_IDS_OPENFILE,
   OFN_HIDEREADONLY | OFN_FILEMUSTEXIST, TRUE, NULL))
  return; // open cancelled
 AfxGetApp()->OpenDocumentFile(newName);
  // if returns NULL, the user has already been alerted
}

很顯然,該函數首先調用DoPromptFileName函數來獲得一個文件名,然后在繼續后續的打開過程。

順這這個線索下去,我們一定能找到插入我們文件打開對話框的位置。由于這不是我們研究的重點,后續的分析我就不再詳述。

實例三:內存訪問越界

在Debug版本的VC程序中,程序會給每塊new出來的內存,預留幾個字節作為越界檢測之用。在釋放內存時,系統會檢查這幾個字節,判斷是否有內存訪問越界的可能。

我們借用前一個實例程序,在CTest1App::InitInstance的開頭添加以下幾行代碼:

    char * p = new char[10];
    memset(p,0,100);
    delete []p;
    return FALSE;

很顯然,這段代碼申請了10字節內存,但是使用了100字節。我們在memset(p,0,100);這行加一個斷點,然后執行程序,斷點到達后,我們觀察p指向的內存的值(利用Debug工具條的Memory功能),可以發現它的值是:

  CD CD CD CD CD CD CD CD
  CD CD FD FD FD FD FD FD
  00 00 00 00 00 00 00 00
  ......

根據經驗,p實際被分配了16個字節,后6個字節用于保護。我們按F5全速執行程序,會發現如下的錯誤信息被彈出:

   Debug Error!
   Program: c:\temp\test1\Debug\test1.exe
   DAMAGE: after normal block (#55) at 0x00421AB0
   Press Retry to debug the application

該信息提示,在正常內存塊0x00421AB0后的內存被破壞(內存訪問越界),我們點擊Retry進入調試狀態,發現調用堆棧是:

_free_dbg_lk(void * 0x00421ab0, int 1) line 1033 + 60 bytes
_free_dbg(void * 0x00421ab0, int 1) line 970 + 13 bytes
operator delete(void * 0x00421ab0) line 351 + 12 bytes
CTest1App::InitInstance() line 54 + 15 bytes

很顯然,這個錯誤是在調用delete時遇到的,出現在CTest1App::InitInstance() line 54 + 15 bytes之處。我們很容易根據這個信息找到,是在釋放哪塊內存時出現問題,之后,我們只需要根據這個內存的訪問過程確定哪兒出錯,這將大大降低調試的難度。

實例四:子類化

子類化是我們修改一個現有控件實現新功能的常用方法,我們借用實例一中的Debug對話框工程來演示我過去學習子類化的一個故事。我們創建一個缺省的名為Debug的對話框工程,并按照下列步驟進行實例化:

  1. 在對話框資源中增加一個Edit控件
  2. 用class wizard為CEdit派生一個類CMyEdit(由于今天不關心子類化的具體細節,因此這個類不作任何修改)
  3. 為Edit控件,增加一個控件類型變量m_edit,其類型為CMyEdit
  4. 在OnInitDialog中增加如下語句:
    m_edit.SubclassDlgItem(IDC_EDIT1,this);

我們運行這個程序,會遇到這樣的錯誤:

				
Debug Assertion Failed! Application:C:\temp\Debug\Debug\Debug.exe File:Wincore.cpp Line:311 For information on how your program can cause an assertion failure, see Visual C++ documentation on asserts. (Press Retry to debug the application)

點擊Retry進入調試狀態,我們可以看到調用堆棧為:

CWnd::Attach(HWND__ * 0x000205a8) line 311 + 28 bytes
CWnd::SubclassWindow(HWND__ * 0x000205a8) line 3845 + 12 bytes
CWnd::SubclassDlgItem(unsigned int 1000, CWnd * 0x0012fe34 {CDebugDlg hWnd=0x001d058a}) line 3883 + 12 bytes
CDebugDlg::OnInitDialog() line 120

可以看出在Attach句柄時出現問題,出問題行的代碼為:

    ASSERT(m_hWnd == NULL);  

這說明我們在子類化時不應該綁定控件,我們刪除CDebugDialog::DoDataExchange中的下面一行:

    DDX_Control(pDX, IDC_EDIT1, m_edit);
問題就得到解決

總結

簡而言之,call stack是調試中必須掌握的一個技術,但是程序員需要豐富的經驗才能很好的掌握和使用它。你不僅僅需要熟知C++語法,還需要對相關的平臺、軟件設計思路有一定的了解。我的文章只能算一個粗淺的介紹,畢竟我在這方面也不算高手。希望對新進有一定的幫助。

posted on 2006-07-11 13:39 楊粼波 閱讀(361) 評論(0)  編輯 收藏 引用


只有注冊用戶登錄后才能發表評論。
網站導航: 博客園   IT新聞   BlogJava   博問   Chat2DB   管理


青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            伊大人香蕉综合8在线视| 亚洲第一在线综合网站| 亚洲一区二区三区777| 亚洲精品免费一区二区三区| 欧美激情乱人伦| 999在线观看精品免费不卡网站| 亚洲激情校园春色| 欧美日韩国产亚洲一区 | 香蕉成人久久| 国产日韩精品一区二区浪潮av| 欧美综合激情网| 久久人人爽爽爽人久久久| 亚洲福利视频在线| 日韩午夜在线| 国产一区二区三区在线观看免费| 噜噜噜躁狠狠躁狠狠精品视频| 欧美电影免费观看大全| 亚洲视频成人| 欧美在线播放高清精品| 亚洲精品1区2区| 亚洲一区二区三区在线视频| 国内精品视频一区| 91久久久亚洲精品| 国产一区二区日韩精品欧美精品| 免费日韩一区二区| 国产精品第三页| 欧美v日韩v国产v| 国产精品啊啊啊| 欧美成人中文字幕| 国产精品一区=区| 亚洲高清久久久| 国产精品美女主播| 亚洲第一精品福利| 国产日韩欧美在线| 日韩性生活视频| 在线观看日韩www视频免费| 99ri日韩精品视频| 在线成人中文字幕| 午夜激情亚洲| 9国产精品视频| 久久综合国产精品| 欧美在线视频播放| 欧美日韩免费观看一区三区| 欧美成人精品1314www| 国产农村妇女精品一区二区| 99www免费人成精品| 亚洲欧洲在线播放| 久久精品国产视频| 欧美在线一二三区| 国产精品扒开腿做爽爽爽视频| 欧美肥婆在线| 雨宫琴音一区二区在线| 性色av一区二区怡红| 亚洲午夜久久久| 欧美精品在线免费| 亚洲国产岛国毛片在线| 精品成人一区二区三区四区| 亚洲一区二区三区在线视频| 亚洲午夜影视影院在线观看| 欧美精品久久久久久| 亚洲高清av| 亚洲黄色大片| 欧美电影免费观看高清完整版 | 亚洲美女精品一区| 久久性色av| 另类激情亚洲| 在线看不卡av| 老司机午夜精品视频| 欧美国产1区2区| 亚洲国产精品视频一区| 两个人的视频www国产精品| 久久综合狠狠综合久久综合88| 国产区亚洲区欧美区| 欧美在线不卡| 噜噜爱69成人精品| 亚洲国产日韩欧美一区二区三区| 欧美v国产在线一区二区三区| 欧美大胆人体视频| 99精品视频免费观看视频| 欧美精品一区二区高清在线观看| 亚洲国产日韩在线| 一区二区三区高清在线| 国产精品海角社区在线观看| 亚洲特色特黄| 巨胸喷奶水www久久久免费动漫| 亚洲电影毛片| 欧美日韩激情小视频| 亚洲一区二区四区| 久久久久综合网| 91久久精品美女| 欧美日韩免费区域视频在线观看| 亚洲香蕉在线观看| 久久免费视频观看| 亚洲伦伦在线| 国产精品天天看| 久久综合精品一区| 一区二区三区欧美亚洲| 久久久一区二区三区| 亚洲福利电影| 国产精品国产三级国产aⅴ无密码 国产精品国产三级国产aⅴ入口 | 国内精品久久久久久久影视麻豆| 麻豆精品网站| 亚洲图片在线| 欧美成人精品在线视频| 亚洲最黄网站| 激情欧美一区二区三区| 欧美另类高清视频在线| 欧美在线亚洲在线| 99热这里只有精品8| 老巨人导航500精品| 亚洲视频日本| 亚洲国产一区二区三区青草影视| 欧美四级在线| 免费观看亚洲视频大全| 亚洲欧美日韩精品久久| 亚洲七七久久综合桃花剧情介绍| 香蕉久久夜色| 亚洲视频二区| 亚洲精品中文字幕在线| 国产亚洲人成a一在线v站 | 欧美日韩成人在线播放| 久久不射中文字幕| 夜夜夜久久久| 亚洲黄色有码视频| 久久天天躁夜夜躁狠狠躁2022 | 国产一区av在线| 国产精品jizz在线观看美国| 久久综合色88| 久久成年人视频| 亚洲自拍啪啪| 亚洲深夜福利在线| 一本到12不卡视频在线dvd| 欧美黑人一区二区三区| 美女露胸一区二区三区| 欧美一区二区三区视频| 亚洲综合色网站| 亚洲亚洲精品在线观看 | 亚洲国产精品va| 黄色日韩精品| 国内精品久久久久影院 日本资源 国内精品久久久久伊人av | 亚洲视频www| 一本久道久久综合婷婷鲸鱼| 亚洲国产精品久久久久久女王| 欧美成人精品1314www| 免费在线看一区| 免费试看一区| 亚洲成色777777女色窝| 欧美激情成人在线| 欧美激情一区二区三区成人| 欧美国产日韩在线| 亚洲国产精品成人综合| 欧美激情一区二区三区 | 久久成人国产精品| 久久国产加勒比精品无码| 欧美一区观看| 久久综合999| 欧美高清一区| 99热精品在线| 亚洲欧美在线一区| 久久国产福利| 欧美福利视频网站| 欧美色区777第一页| 欧美日韩一级视频| 国产免费成人| 极品裸体白嫩激情啪啪国产精品| 亚洲第一综合天堂另类专| 亚洲精选一区二区| 亚洲欧美日本国产专区一区| 久久国产一二区| 欧美成人午夜视频| 一区二区三区色| 久久精品国产999大香线蕉| 欧美 日韩 国产精品免费观看| 欧美美女操人视频| 国产私拍一区| 亚洲伦理在线| 久久久国产一区二区三区| 亚洲大胆美女视频| 亚洲男人的天堂在线aⅴ视频| 欧美一区二区三区在线视频| 狂野欧美一区| 国产精品久久久久永久免费观看| 国内精品久久久久久久97牛牛| 日韩午夜视频在线观看| 午夜在线一区二区| 亚洲高清不卡一区| 欧美亚洲免费高清在线观看| 欧美a级理论片| 国产女人精品视频| 亚洲精品视频在线看| 久久黄色网页| 一本色道久久综合亚洲精品按摩| 欧美一区二区三区在线看| 欧美精品色一区二区三区| 国产欧美一区二区白浆黑人| 亚洲精品国产日韩| 久久综合精品国产一区二区三区| 9久草视频在线视频精品| 久久精品国产久精国产爱| 欧美日精品一区视频|