【问题标题】:clang-tidy: How to suppress C++ warnings in C header file?clang-tidy:如何抑制 C 头文件中的 C++ 警告?
【发布时间】:2021-09-04 23:55:53
【问题描述】:

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

#ifdef __cplusplus
extern "C" {
#endif

...

#ifdef __cplusplus
}
#endif

然而,当我将它包含在 .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。

【问题讨论】:

  • 您可以尝试使用inline suppressions 来禁用这些警告。
  • @icebp 他可能会,但他犯的“生态”错误不应该被忽视。标准标头包含永远不应在 extern 块内,并且不建议包含 C 版本的标头(正式为 UB)

标签: c++ c static-analysis clang-tidy


【解决方案1】:

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

  • 有些行包含遗留或不是非常好的 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

【讨论】:

    【解决方案2】:

    那些 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
    

    你会有一个具有以下结构的标题

    // 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
    

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

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

    【讨论】:

    • @HolyBlackCat 你是说extern "C" { #include &lt;stdlib.h&gt; } 是符合标准的相当于#include &lt;cstdlib&gt; 的OP 暗示?它本身并不是错误的(它可能是),具体取决于实现,如果 cstdlib 仅包含包含 C++ 和 C 代码的 stdlib.h 并且某些符号的运行时名称不同。 cstdlib 有时包含来自其他位置的一些标头或有自己的实现。它没有定义。
    • @KamilCuk is an implementation detail,是的,这就是我领先的地方。 . extern "C" { #include &lt;stdlib.h&gt; } 在 C++ 代码中,无论它是否真的会链接,也是特定于实现的,当使用几个专有编译器完成类似的事情时,我遇到了链接问题。它与 std 命名空间无关,而是与头文件的特定于实现的内容有关,它声明了一些供编译器使用的东西。
    • 我认为 OP 作为一个明智的人,会将其包含在 extern "C" { 之上。那么它将是有效的。如果你把它放在下面,那么是的,它可能是 UB。
    • @HolyBlackCat 我不知道如何解释“其(标题)内容包含在那些中”的声明。我以前看到过,甚至是由非常昂贵的 GIS 系统的标题完成的,以及类似的东西#define max#define data
    猜你喜欢
    • 2017-01-24
    • 2021-06-03
    • 2019-11-04
    • 2010-12-24
    • 2011-02-02
    • 1970-01-01
    • 2018-04-10
    相关资源
    最近更新 更多