我正在爲Windows和Unix編寫一個跨平臺的C++程序。在窗口一側,代碼將編譯並執行沒有問題。在Unix端,它會編譯,但是當我嘗試運行它時,我得到了分段錯誤。我最初的直覺是指針有問題。修復C++中的分割錯誤
找到並修復分段故障錯誤的好方法是什麼?
我正在爲Windows和Unix編寫一個跨平臺的C++程序。在窗口一側,代碼將編譯並執行沒有問題。在Unix端,它會編譯,但是當我嘗試運行它時,我得到了分段錯誤。我最初的直覺是指針有問題。修復C++中的分割錯誤
找到並修復分段故障錯誤的好方法是什麼?
與-g
編譯應用程序,那麼你就必須調試符號二進制文件。使用gdb
打開gdb控制檯。
使用file
並將其應用程序的二進制文件傳遞到控制檯。
使用run
並傳入您的應用程序需要啓動的任何參數。
做些什麼導致分割錯誤。
在gdb
控制檯類型bt
得到分段錯誤的堆棧跟蹤。
在Unix上,您可以使用valgrind來查找問題。它免費且強大。如果您寧願自己動手,您可以重載新操作符和刪除操作符,以在每個新對象之前和之後設置一個配置,其中您有1個字節,其中包含0xDEADBEEF
。然後跟蹤每次迭代發生的情況。這可能無法捕捉到所有內容(您甚至不能保證觸及這些字節),但它在Windows平臺上過去對我來說很有用。
有時,崩潰本身並不是問題的真正原因 - 也許內存在早期被粉碎,但腐敗顯現出來需要一段時間。檢查出valgrind,它有很多指針問題檢查(包括數組邊界檢查)。它會告訴你問題從哪裏開始,而不僅僅是發生崩潰的線路。
問題出現之前,儘量避免它儘可能:
使用適當的工具進行調試。在Unix上:
最後我會推薦平時的事情。程序可讀性越高,可維護性越強,清晰整潔,最容易進行調試。
我不知道任何方法來解決這樣的事情。我認爲不可能爲手頭的問題提出一個問題,那就是你的程序的行爲是不確定的(我不知道SEGFAULT並不是由某種UB引起的) 。
有各種各樣的「方法論」來避免問題發生。一個重要的是RAII。
除此之外,你只需要投入你最好的精神能量。
是的,指針有問題。很可能你正在使用一個沒有正確初始化的程序,但也有可能你用雙重空閒或其他方式搞亂了你的內存管理。
爲了避免未初始化的指針作爲局部變量,儘可能遲的嘗試聲明它們,最好(並不總是可能的),當它們可以用有意義的值初始化時。通過檢查代碼,說服他們在使用之前會有價值。如果您遇到困難,請將它們初始化爲空指針常量(通常寫爲NULL
或0
)並檢查它們。
要避免未初始化的指針作爲成員值,請確保它們已在構造函數中正確初始化,並在複製構造函數和賦值運算符中正確處理。雖然可以進行其他初始化,但不要依賴內存管理的init
函數。
如果你的類不需要拷貝構造函數或賦值操作符,你可以將它們聲明爲私有成員函數,並且永遠不要定義它們。這會導致編譯器錯誤,如果他們明確或隱式地使用。
適用時使用智能指針。這裏最大的好處是,如果你堅持使用它們並且一致地使用它們,你就完全可以避免寫入delete
,而且沒有東西會被雙重刪除。
儘可能使用C++字符串和容器類,而不是C風格的字符串和數組。考慮使用.at(i)
而不是[i]
,因爲這會強制邊界檢查。至少在調試模式下,看看您的編譯器或庫是否可以設置爲檢查[i]
上的界限。分段錯誤可能由緩衝區溢出引起,這些緩衝區溢出將垃圾寫入完美的指針。
做這些事情將大大降低分段錯誤和其他內存問題的可能性。他們無疑將無法解決所有問題,這就是爲什麼你應該不時地使用valgrind,而當你沒有問題的時候,以及valgrind和gdb。
以及這將是4個字節,而不是1 ...但原則是好的。 – 2010-09-15 15:57:36
我可以鏈接到我的[非侵入式堆調試器](http://stackoverflow.com/questions/2835416)嗎? :-) – fredoverflow 2010-09-15 16:31:08
去吧。我們都在幫助別人,所以任何可以幫助的東西都應該加上。 – wheaties 2010-09-15 17:03:00