在實際的項目中,當項目的代碼量不斷增長的時候,你會發現愈來愈難管理和跟蹤其各個組件,如其不善,很容易就引入BUG。所以、咱們應該掌握一些能讓咱們程序更加健壯的方法。數組
這篇文章提出了一些建議,能有引導咱們寫出更增強壯的代碼,以免產生災難性的錯誤。即便、由於其複雜性和項目團隊結構,你的程序目前不遵循任何編碼規則,按照下面列出的簡單的規則能夠幫助您避免大多數的崩潰狀況。ide
先來介紹下做者開發一些軟件(CrashRpt),你能夠http://code.google.com/p/crashrpt/網站上下載源代碼。CrashRpt 顧名思義軟件崩潰記錄軟件(庫),它可以自動提交你電腦上安裝的軟件錯誤記錄。它經過以太網直接將這些錯誤記錄發送給你,這樣方便你跟蹤軟件問題,並及時修改,使得用戶感受到每次發佈的軟件都有很大的提升,這樣他們天然很高興。函數
圖 一、CrashRpt 庫檢測到錯誤彈出的對話框網站
在分析接收的錯誤記錄的時候,咱們發現採用下文介紹的方法可以避免大部分程序崩潰的錯誤。例如、局部變量未初始化致使數組訪問越界,指針使用前未進行檢測(NULL)致使訪問訪問非法區域等。google
我已經總結了幾條代碼設計的方法和規則,在下文一一列出,但願可以幫助你避免犯一些錯誤,使得你的程序更加健壯。編碼
使用未初始化的局部變量是引發程序崩潰的一個比較廣泛的緣由,例如、來看下面這段程序片斷:設計
// Define local variables BOOL bExitResult; // This will be TRUE if the function exits successfully FILE* f; // Handle to file TCHAR szBuffer[_MAX_PATH]; // String buffer // Do something with variables above...
上面的這段代碼存在着一個潛在的錯誤,由於沒有一個局部變量初始化了。當你的代碼運行的時候,這些變量將被默認負一些錯誤的數值。例如bExitResult 數值將被負爲-135913245 ,szBuffer 必須以「\0」結尾,結果不會。所以、局部變量初始化時很是重要的,以下正確代碼:
// Define local variables // Initialize function exit code with FALSE to indicate failure assumption BOOL bExitResult = FALSE; // This will be TRUE if the function exits successfully // Initialize file handle with NULL FILE* f = NULL; // Handle to file // Initialize string buffer with empty string TCHAR szBuffer[_MAX_PATH] = _T(""); // String buffer // Do something with variables above...
注意:有人說變量初始化會引發程序效率下降,是的,確實如此,若是你確實很是在意程序的執行效率,去除局部變量初始化,你得想好其後果。指針
許多Windows API都接受或則返回一些結構體參數,結構體若是沒有正確的初始化,也頗有可能引發程序崩潰。你們可能會想起用ZeroMemory宏或者memset()函數去用0填充這個結構體(對結構體對應的元素設置默認值)。可是大部分Windows API 結構體都必須有一個cbSIze參數,這個參數必須設置爲這個結構體的大小。code
看看下面代碼,如何初始化Windows API結構體參數:對象
NOTIFYICONDATA nf; // WinAPI structure memset(&nf,0,sizeof(NOTIFYICONDATA)); // Zero memory nf.cbSize = sizeof(NOTIFYICONDATA); // Set structure size! // Initialize other structure members nf.hWnd = hWndParent; nf.uID = 0; nf.uFlags = NIF_ICON | NIF_TIP; nf.hIcon = ::LoadIcon(NULL, IDI_APPLICATION); _tcscpy_s(nf.szTip, 128, _T("Popup Tip Text")); // Add a tray icon Shell_NotifyIcon(NIM_ADD, &nf);
注意:千萬不要用ZeroMemory和memset去初始化那些包括結構體對象的結構體,這樣很容易破壞其內部結構體,從而致使程序崩潰.
// Declare a C++ structure struct ItemInfo { std::string sItemName; // The structure has std::string object inside int nItemValue; }; // Init the structure ItemInfo item; // Do not use memset()! It can corrupt the structure // memset(&item, 0, sizeof(ItemInfo)); // Instead use the following item.sItemName = "item1"; item.nItemValue = 0; 這裏最好是用結構體的構造函數對其成員進行初始化. // Declare a C++ structure struct ItemInfo { // Use structure constructor to set members with default values ItemInfo() { sItemName = _T("unknown"); nItemValue = -1; } std::string sItemName; // The structure has std::string object inside int nItemValue; }; // Init the structure ItemInfo item; // Do not use memset()! It can corrupt the structure // memset(&item, 0, sizeof(ItemInfo)); // Instead use the following item.sItemName = "item1"; item.nItemValue = 0;