修复C ++中的分段错误

时间:2010-09-15 15:09:05

标签: c++ debugging segmentation-fault

我正在为Windows和Unix编写一个跨平台的C ++程序。在Window端,代码将编译并执行没有问题。在Unix方面,它会编译然而当我尝试运行它时,我得到一个分段错误。我最初的预感是指针存在问题。

找到并修复细分错误的好方法是什么?

6 个答案:

答案 0 :(得分:96)

  1. 使用-g编译您的应用程序,然后您将在二进制文件中包含调试符号。

  2. 使用gdb打开gdb控制台。

  3. 使用file并将其应用程序的二进制文件传递给控制台。

  4. 使用run并传入您的应用程序需要启动的任何参数。

  5. 做一些事情导致分段错误

  6. bt控制台中键入gdb以获取分段错误的堆栈跟踪。

答案 1 :(得分:29)

有时崩溃本身并不是问题的真正原因 - 也许记忆在早些时候被粉碎,但腐败显示需要一段时间。查看valgrind,它有很多指针问题检查(包括数组边界检查)。它会告诉你启动的问题,而不仅仅是发生崩溃的行。

答案 2 :(得分:16)

在问题出现之前,尽量避免使用它:

  • 尽可能多地编译和运行代码。找到有缺陷的部分会更容易。
  • 尝试封装低级别/容易出错的例程,以便您很少需要直接使用内存(注意程序的模型化)
  • 维护一个测试套件。概述当前正在工作的东西,什么不再工作等,将帮助您找出问题所在(Boost test是一个可能的解决方案,我不自己使用它,但文档可以帮助了解必须显示哪种信息。)

使用适当的工具进行调试。在Unix上:

  • GDB可以告诉您编程崩溃的位置,并让您了解在什么情况下。
  • Valgrind将帮助您检测许多与内存相关的错误。
  • 使用GCC,您也可以使用mudflap 使用GCC和Clang,您可以使用Address/Memory Sanitizer。它可以检测出Valgrind没有的一些错误,并且性能损失更轻。

最后我会推荐通常的事情。程序的可读性,可维护性,清晰性和整洁程度越高,调试就越容易。

答案 3 :(得分:3)

在Unix上,你可以使用valgrind来查找问题。它是免费且强大的。如果你想自己做,你可以重载new和delete运算符来设置一个配置,你在每个新对象之前和之后有一个带0xDEADBEEF的字节。然后跟踪每次迭代发生的事情。这可能无法捕获所有内容(您无法保证甚至触及这些字节)但过去它在Windows平台上对我有用。

答案 4 :(得分:2)

是的,指针存在问题。很可能你正在使用一个没有正确初始化的,但也有可能你用双倍释放或其他一些东西来搞乱你的内存管理。

为了避免未初始化的指针作为局部变量,尝试尽可能晚地声明它们,当它们可以用有意义的值初始化时,最好(并且这并不总是可行)。通过检查代码,说服自己在使用之前会有一个价值。如果您遇到困难,请将它们初始化为空指针常量(通常写为NULL0)并检查它们。

要避免未初始化的指针作为成员值,请确保它们在构造函数中正确初始化,并在复制构造函数和赋值运算符中正确处理。尽管您可以进行其他初始化,但不要依赖init函数进行内存管理。

如果您的类不需要复制构造函数或赋值运算符,则可以将它们声明为私有成员函数,而不是定义它们。如果明确或隐式使用它们,将导致编译器错误。

适用时使用智能指针。这里的最大优点是,如果你坚持使用它们并且始终如一地使用它们,你就可以完全避免写delete而且不会删除任何内容。

尽可能使用C ++字符串和容器类,而不是C风格的字符串和数组。考虑使用.at(i)而不是[i],因为这会强制进行边界检查。查看您的编译器或库是否可以设置为检查[i]上的边界,至少在调试模式下是这样。分段错误可能是由缓冲区溢出引起的,它会在完美的指针上写入垃圾。

做这些事情将大大降低分段错误和其他内存问题的可能性。他们无疑无法解决所有问题,这就是为什么你应该在你没有问题时偶尔使用valgrind,以及在你做的时候使用valgrind和gdb。

答案 5 :(得分:0)

我不知道有任何方法可用于修复此类问题。我不认为有可能想出一个问题,因为你的程序的行为是未定义的(我不知道SEGFAULT不是由某种UB引起的任何情况)

在问题出现之前,有各种各样的“方法论”可以避免这个问题。一个重要的是RAII。

除此之外,你只需要投入最好的精神能量。