博客 阅读时间 4 分钟

Clang 能告诉您关于 Visual C++ 项目的哪些信息?

分享本文
What Can Clang Tell You About Your Visual C++ Projects?

每个编译器在构建后都能报告大量警告。除非您决定将它们视为错误,否则这些警告不会阻止代码编译。请花时间检查这些警告,而不是忽略它们。编译器警告往往是潜在 Bug 的指示信号,否则这些问题可能要到运行时才会暴露出来。

Clang 是一个拥有许多实用功能的 C/C++/Objective-C 编译器。以下是其主要的面向用户的特性:

  • 编译速度快,内存占用低。
  • 富有表现力的诊断信息。
  • 与 GCC 兼容。

在本文中,我们将重点介绍 Clang 富有表现力的诊断信息,以及如何为 Visual C++ 项目获取它们。

Clang 团队的目标是提供尽可能清晰、信息量大的错误消息。他们努力让这些消息对命令行编译器来说尽可能用户友好。为此,Clang 会精确指出代码中的问题所在。这是通过一个将错误信息加工为用户友好消息的诊断引擎来实现的。

为了展示 Clang 诊断的好处,让我们分别用 Visual C++ 和 Clang 编译一个最小的 C++ 源文件,比较它们报告的警告。两个编译器都启用所有警告。

clang1

微软 C++ 编译器报告了以下警告:

  • warning C4100:"n":未引用的形参

Clang 报告了三条警告:

  • 函数"Print"没有先前的原型声明
  • 使用了旧式类型转换
  • 未使用的参数"n"

Clang 的有趣之处在于,它还会报告与编码最佳实践相关的诊断。例如,之所以报告"函数 Print 没有先前的原型声明"这条警告,是因为 Print 没有被声明为静态函数,所以它可能被其他源文件使用——在这种情况下,建议将其声明放在头文件中。

为了更具体地了解 Clang 的诊断,让我们分别用 Clang 和微软编译器编译一个开源 C++ 项目,比较它们报告的警告类型。

我们将以"7-Zip"项目为例,只编译 Gui.vcproj 模块。我们只关注与项目源代码相关的警告,不涉及外部包含文件。

微软编译器报告了这类警告:

  • 在数据成员之后添加了字节填充。
  • 类型转换问题。
  • 函数未内联。
  • 类有虚函数,但析构函数不是虚的。
  • 自 Visual C++ 7.1 起 catch(…) 的语义已改变;不再捕获结构化异常(SEH)。
  • 类型转换问题。
  • 在枚举"NCommandType::EEnum"的 switch 中,枚举值"kInfo"没有被任何 case 标签显式处理。
  • "GetVersionExA":已被声明为弃用。
Clang 编译器报告了这类警告:
  • 使用了旧式类型转换
  • 缺少字段"MinLen"的初始化器
  • 宏未被使用
  • 声明需要一个全局构造函数
  • 声明需要一个退出时的析构函数
  • 类型转换问题
  • 类型转换问题
  • 枚举值"kWithoutPrompt"、"kAutoRename"和"kAutoRenameExisting"未在 switch 中处理
  • ?: 的操作数改变了符号性:从"const int"变为"unsigned int"
  • 声明遮蔽了一个局部变量
  • ISO C++11 不允许从字符串字面量转换为"LPSTR"(即"char *")
  • 函数没有先前的原型声明
  • 比较问题
  • "GetVersionExA":已被声明为弃用
  • 动态异常规范已被弃用
  • "||"中包含"&&"
  • "CBenchRandomGenerator"没有外联的虚方法定义;其虚函数表将在每个翻译单元中生成
  • 对拥有虚函数但析构函数非虚的"CBenchmarkInStream"调用了 delete
  • "CBenchmarkInStream"有虚函数但析构函数非虚
  • 相等比较的结果未被使用
  • 将"INT_PTR"(即"int")类型的变量显式赋值给它自己
  • 添加显式大括号以避免悬空的 else

我们可以看到,Clang 报告的实用警告比微软编译器更多;其中一些通常只有静态分析工具才会报告。认真对待这些警告是值得的,因为它们可能揭示许多 Bug。

如何为您的 Visual C++ 项目获取 Clang 诊断信息?

Clang 诊断信息帮助开发者提高其 C/C++ 源代码的质量,因此为 Visual C++ 项目获取它们是很有用的。

第一种选择是使用 Clang 编译您的项目;这里有一篇MSDN 文章向您展示如何在 VS 中使用 Clang 作为编译器。

第二种选择是使用CppDepend分析您的 Visual Studio 项目,它使用 Clang 作为前端解析器并报告其所有诊断信息。CppDepend对开源社区免费

下面的查询返回所有 Clang 诊断信息:

clang6

7-Zip 应用程序的 Gui 项目只有 1 万行代码,却有 1186 条诊断。对于中大型项目,您可能会有成千上万条诊断。在这种情况下,过滤它们、只检索特定类型的警告就很有用。

例如,我们可以修改前面的查询,只获取与弃用用法相关的警告。

clang8

结论:

警告往往是潜在 Bug 的指示信号,不应被忽视。Clang 报告许多实用的诊断信息,包括一些与编码最佳实践相关的信息;处理这些警告可以帮助提高项目源代码的质量。

分享本文