13

有没有办法知道你的程序在 C++(甚至 C)中是否有未定义的行为,而不是记住整个规范?

我问的原因是我注意到很多程序在调试但没有发布的情况下是由于未定义的行为。如果有一个工具至少可以帮助发现 UB,那就太好了,所以我们知道存在问题的可能性。

4

10 回答 10

17

良好的编码标准。保护你免受自己的伤害。这里有一些想法:

  1. 代码必须在最高警告级别编译......没有警告。(换句话说,当设置为最高级别时,您的代码根本不能触发任何警告。)为所有项目打开错误警告标志。

    当您使用其他人的库时,这确实意味着一些额外的工作,因为他们可能没有这样做。您还会发现有些警告毫无意义……根据您的团队决定单独关闭这些警告。

  2. 始终使用RAII

  3. 永远不要使用 C 风格的演员表! 绝不!- 我认为有一些罕见的情况是你必须打破它,但你可能永远找不到它们。

  4. 如果您必须reinterpret_cast或强制转换为,void则使用包装器以确保您始终向/从同一类型进行转换。换句话说,将您的指针/对象包装在 a 中boost::any并将指向它的指针转换为您需要的任何内容,并且在另一边执行相同的操作。为什么?因为您将始终知道要从什么类型开始reinterpret_cast,并且在此boost::any之后将强制您转换为正确的类型。这是你能得到的最安全的。

  5. 始终 在声明时初始化变量(或在类中的构造函数初始化程序中)。

还有更多,但这些是一些非常重要的开始。

没有人能记住标准。我们中级到高级 C++ 程序员所做的是使用我们知道是安全的构造并保护我们自己免受人性的伤害……除非我们必须这样做,否则我们不会使用不安全的构造,然后我们会格外小心以确保危险都包裹在一个很好的安全界面中,该界面经过了地狱和回来的测试。

要记住所有语言通用的一件重要事情是:

使您的构造易于正确使用且难以错误使用

于 2010-06-10T16:07:39.550 回答
5

不可能在所有情况下都检测到未定义的行为。例如,考虑x = x++ + 1;. 如果你熟悉这种语言,你就知道它是 UB。现在,*p = (*p)++ + 1;显然也是UB,但是呢*q = (*p)++ + 1;?那是 UB if q == p,但除此之外它是定义的(如果看起来很尴尬)。在给定的程序中,很可能证明这一点p并且q在到达那条线时永远不会相等,但一般来说这是做不到的。

为了帮助发现 UB,请使用您拥有的所有工具。好的编译器至少会在更明显的情况下发出警告,尽管您可能必须使用一些编译器选项才能获得最佳覆盖率。如果您有更多的静态分析工具,请使用它们。

代码审查也非常适合发现此类问题。如果您有多个开发人员可用,请使用它们。

于 2010-06-10T16:09:07.193 回答
3

静态代码分析工具,例如PC-Lint可以在这里提供很多帮助

于 2010-06-10T16:00:39.147 回答
2

好吧,这篇文章涵盖了大多数方面..

于 2010-06-10T15:54:51.860 回答
2

我认为您可以使用一种工具来发现会导致未定义行为的错误

我猜你可以使用定理证明器(我只知道 Coq)来确保你的程序做你想要的。

于 2010-06-10T15:59:14.890 回答
2

clang当遇到未定义的行为时,会努力产生警告。

于 2010-06-10T16:07:52.297 回答
1

我不知道有任何软件工具可以检测所有形式的 UB。显然,使用编译器的警告以及可能的 lint 或其他静态代码检查器可以提供很大帮助。

另一件有很大帮助的事情就是经验:您对语言进行的编程越多,您就会越多地看到看似可疑的结构,并且能够在流程的早期捕获它们。

于 2010-06-10T15:56:07.087 回答
0

不幸的是,没有办法检测所有的 UB。你必须解决停机问题才能做到这一点。

你能做的最好的事情就是尽可能多地了解规则,当你有疑问时查阅它,并与其他程序员一起检查(通过结对编程、代码审查或只是 SO 问题)

使用尽可能多的警告进行编译,并在多个编译器下进行编译会有所帮助。并且通过 Valgrind 等静态分析工具运行代码可以检测出很多问题。

但最终,没有工具可以检测到这一切。

另一个问题是许多程序实际上必须依赖 UB。一些 API 需要它,并假设“它适用于所有健全的编译器”。OpenGL 在一种或两种情况下会这样做。Win32 API 甚至不能在符合标准的编译器下编译。

所以即使你有一个神奇的 UB 检测工具,它仍然会被不受你控制的情况所绊倒。

于 2010-06-10T16:40:02.330 回答
-1

很简单:不要做你不知道你能做的事情。

  • 当您不确定或有可疑感时,请查看参考资料
于 2010-06-10T16:13:44.403 回答
-3

一个好的编译器,例如英特尔 C++ 编译器,应该能够发现 99% 的未定义行为情况。您需要调查要使用的标志和开关。和以往一样,阅读手册。

于 2010-06-10T15:54:51.283 回答