clang-tidy:如何抑制 C 头文件中的 C++ 警告?

Wol*_*ler 7 c c++ static-analysis clang-tidy

我有一个包含在 C 和 C++ 源文件中的 .h 文件。它的内容被包裹在

#ifdef __cplusplus
extern "C" {
#endif

...

#ifdef __cplusplus
}
#endif
Run Code Online (Sandbox Code Playgroud)

然而,当我将它包含在 .cpp 文件中时,clang-tidy 会发出特定于 C++ 的消息,例如

  • 警告:包括“stdbool.h”在 C++ 中无效;考虑删除它 [hicpp-deprecated-headers,modernize-deprecated-headers]
  • 警告:包含已弃用的 C++ 头文件“stdlib.h”;考虑使用“cstdlib”代替 [hicpp-deprecated-headers,modernize-deprecated-headers]
  • 警告:使用 'using' 而不是 'typedef' [modernize-use-using]

我喜欢这些检查,我想让它们在我的 clang-tidy 配置中保持活动状态,但当然仅适用于 C++ 代码。我无法更改头文件以使用using代替typedef<cstdlib>代替,<stdlib.h>因为它也包含在 C 源中,因此extern "C".

有什么方法可以告诉 clang-tidy 将代码extern "C"视为 C 而不是 C++,即使包含在 .cpp 文件中?

clang-tidy 版本是 12.0.0。

Ser*_*sta 5

Clang-Tidy 可以利用特殊NOLINTNOLINTNEXTLINE注释来抑制特定行的警告。它完全适合您的用例:

  • 某些行包含旧版或不严格的 C++ 代码
  • 这样做有一个很好的理由——这里的代码必须可由 C 编译器解析。

使用它时的更高风险是滥用它并在可以改进编码的情况下消除警告。但是,当您需要从 C 和 C++ 源代码使用标头,并且您已经仔细阅读了NOLINTed行两次时,它就完全没问题,至少恕我直言。此外,甚至可以指示静音警告:

#ifdef __cplusplus
extern "C" {
#endif
// NOLINTNEXTLINE(hicpp-deprecated-headers,modernize-deprecated-headers) C compatible code
#include <stdbool.h>
#include <stdlib.h>     // NOLINT C code requires that header
...

#ifdef __cplusplus
}
#endif
Run Code Online (Sandbox Code Playgroud)


Swi*_*Pie -1

这些 C 和 C++ 头文件对于 C++ 来说并不等同。这些警告是合法的,并且表明代码不符合 C++ 标准。

extern "C"仅将声明的函数和变量的链接类型声明为全局且不进行修饰,名称以 C 格式使用。它不会影响使用 C++ 功能声明的对象和函数的使用。它与语言的生态系统无关。更重要的是,如果 C++ 标头出现在这些括号内,并且声明的函数最初是在 C++ 链接中,则可能会出现链接错误。

对于 C++,您必须使用#ifdef __cplusplus包含 C++ 替代方案,否则包括 C 替代方案。

代替:

#ifdef __cplusplus
extern "C" {
#endif

#include <stdbool.h>
#include <stdlib.h>

// your declarations

#ifdef __cplusplus
}
#endif
Run Code Online (Sandbox Code Playgroud)

您将拥有具有以下结构的标头

// headers that are universally compatible (3rd party)

#ifdef __cplusplus
#   include <cstdlib>
// other C++ headers
// Your C++ - only declarations (incompatible with C rules) 

extern "C" {
#else
#   include <stdbool.h>
#   include <stdlib.h>
// other C headers
//  C-only declarations (incompatible with C++ rules)

#endif

// your compatible declarations available for both

#ifdef __cplusplus  
}  // extern "C"
#endif
Run Code Online (Sandbox Code Playgroud)

在某些情况下,由于所需的标头包含顺序或声明的依赖性,需要调整此结构。盲目地更改不是由您编写的库头中的声明链接,并且您无法保证这些使用的命名约定和链接类型是一种失礼行为,可能会导致 ODR 违规或链接失败。

typedef 问题很烦人,您可以使用 NOLINT 或命令行选项来抑制,modernize-use-using作为临时措施。一般来说,对于可移植标头,这将通过至少对于结构类型的宏定义来完成。存在一个问题,即 typedef 和别名声明在某些情况下无法通过标准方式进行转换,例如考虑函数指针类型的声明。