如何写出优雅的C++代码

开发 后端
工欲善其事必先利其器,优雅的代码离不开静态代码检查工具,大家可能平时使用较多的是cppcheck,但今天我想跟大家分享另一个静态代码检查工具clang-tidy。

[[373379]]

本文转载自微信公众号「程序喵大人」,作者程序喵大人 。转载本文请联系程序喵大人公众号。

 工欲善其事必先利其器,优雅的代码离不开静态代码检查工具,大家可能平时使用较多的是cppcheck,但今天我想跟大家分享另一个静态代码检查工具clang-tidy。

不同于cppcheck使用正则表达式进行静态代码分析,clang-tidy是基于语法分析树的静态代码检查工具,虽然它的速度比正则表达式慢一些,但是它检查的更准确、全面,而且不仅可以做静态检查,还可以做一些修复工作,自行添加一些自定义检查规则。

话不多说,上代码:

#include <iostream> 
 
int main() { 
    int a = 1.2; 
    return 0; 

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.

这里有隐式类型转换,可以使用clang-tidy来检测:

~/test$ clang-tidy -checks=* test_lint.cpp -- 
7748 warnings generated. 
/home/wangzhiqiang/test/test_lint.cpp:20:13: warning: implicit conversion from 'double' to 'int' changes value from 1.2 to 1 [clang-diagnostic-literal-conversion] 
    int a = 1.2; 
            ^ 
Suppressed 7747 warnings (7747 in non-user code). 
Use -header-filter=.* to display errors from all non-system headers. Use -system-headers to display errors from system headers as well. 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.

这里也许你有疑问了,这不就是一个普通的编译警告嘛,正常使用编译器也可以检查出来,那再看一段代码:

#include <iostream> 
 
int main() { 
    char* d = NULL
    return 0; 

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.

我们都知道在C++中应该更多的使用nullptr而不是NULL,这里使用了NULL而不是使用nullptr,可能我们在开发过程中没有注意到这种用法,所以clang-tidy派上了用场:

~/test$ clang-tidy -checks=* test_lint.cpp -- 
7748 warnings generated. 
/home/wangzhiqiang/test/test_lint.cpp:20:15: warning: use nullptr [modernize-use-nullptr] 
    char* d = NULL
              ^~~~~ 
              nullptr 
Suppressed 7747 warnings (7747 in non-user code). 
Use -header-filter=.* to display errors from all non-system headers. Use -system-headers to display errors from system headers as well. 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.

再举一个例子:

struct Base { 
    virtual void func() { 
 
    } 
}; 
 
struct Derive : Base { 
    virtual void func() { 
 
    } 
}; 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.

这里可能我们乍一看没有任何问题,其实在C++11里派生类继承父类,重写了某些函数时最好加上override关键字,通过clang-tidy还是可以检测出来:

~/test$ clang-tidy -checks=* test_lint.cpp -- 
7749 warnings generated. 
/home/wangzhiqiang/test/test_lint.cpp:14:18: warning: prefer using 'override' or (rarely) 'final' instead of 'virtual' [hicpp-use-override] 
    virtual void func() { 
    ~~~~~~~~~~~~~^ 
                        override 
Suppressed 7747 warnings (7747 in non-user code). 
Use -header-filter=.* to display errors from all non-system headers. Use -system-headers to display errors from system headers as well. 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.

该工具还可以检查代码是否符合编码规范,例如Google编码规范等,看这段头文件相关代码:

#include <iostream> 
#include <string> 
#include <memory> 
  • 1.
  • 2.
  • 3.

这里其实有一点点问题,头文件引用顺序不满足编码规范,这里其实clang-format都可以检测出来,但clang-tidy也可以检测出来,通过-fix还可以进行自动修复:

~/test$ clang-tidy -checks=* test_lint.cpp -- 
8961 warnings generated. 
/home/wangzhiqiang/test/test_lint.cpp:2:1: warning: #includes are not sorted properly [llvm-include-order
#include <string> 
^        ~~~~~~~~ 
Suppressed 8960 warnings (8960 in non-user code). 
Use -header-filter=.* to display errors from all non-system headers. Use -system-headers to display errors from system headers as well 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.

它还可以检测隐藏的内存泄漏:

int main() { 
    char* ct = (char*)malloc(323); 
    return 0; 

  • 1.
  • 2.
  • 3.
  • 4.

这是使用clang-tidy的检测结果:

~/test$ clang-tidy -checks=* test_lint.cpp -- 
7756 warnings generated. 
/home/wangzhiqiang/test/test_lint.cpp:20:5: warning: initializing non-owner 'char *' with a newly created 'gsl::owner<>' [cppcoreguidelines-owning-memory] 
    char* ct = (char*)malloc(323); 
    ^ 
/home/wangzhiqiang/test/test_lint.cpp:20:5: warning: use auto when initializing with a cast to avoid duplicating the type name [hicpp-use-auto] 
    char* ct = (char*)malloc(323); 
    ^~~~~ 
    auto 
/home/wangzhiqiang/test/test_lint.cpp:20:11: warning: Value stored to 'ct' during its initialization is never read [clang-analyzer-deadcode.DeadStores] 
    char* ct = (char*)malloc(323); 
          ^ 
/home/wangzhiqiang/test/test_lint.cpp:20:11: note: Value stored to 'ct' during its initialization is never read 
/home/wangzhiqiang/test/test_lint.cpp:20:16: warning: C-style casts are discouraged; use static_cast [google-readability-casting] 
    char* ct = (char*)malloc(323); 
               ^~~~~~~~~~~~~     ~ 
               static_cast<char*>( ) 
/home/wangzhiqiang/test/test_lint.cpp:20:16: warning: do not use C-style cast to convert between unrelated types [cppcoreguidelines-pro-type-cstyle-cast
/home/wangzhiqiang/test/test_lint.cpp:20:23: warning: do not manage memory manually; consider a container or a smart pointer [cppcoreguidelines-no-malloc] 
    char* ct = (char*)malloc(323); 
                      ^ 
/home/wangzhiqiang/test/test_lint.cpp:21:5: warning: Potential leak of memory pointed to by 'ct' [clang-analyzer-unix.Malloc] 
    return 0; 
    ^ 
/home/wangzhiqiang/test/test_lint.cpp:20:23: note: Memory is allocated 
    char* ct = (char*)malloc(323); 
                      ^ 
/home/wangzhiqiang/test/test_lint.cpp:21:5: note: Potential leak of memory pointed to by 'ct' 
    return 0; 
    ^ 
Suppressed 7747 warnings (7747 in non-user code). 
Use -header-filter=.* to display errors from all non-system headers. Use -system-headers to display errors from system headers as well 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.

clang-tidy还有很多高端功能,大概可以检测出250种问题,大体主要分为几大类:

  • abseil:检测abseil库的相关问题
  • android:检测Android相关问题
  • boost:检测boost库的相关问题
  • cert:检测CERT的代码规范
  • cpp-core-guidelines:检测是否违反cpp-core-guidelines
  • google:检测是否违反google编码规范
  • llvm:检测是否违反llvm编码规范
  • performance:检测性能相关的问题
  • readability:检测与可读性相关,但又不属于某些编码规范的问题
  • modernize:检测是否使用现代C++11相关的代码问题

而且适用于Windows/Linux/MacOS多平台,还支持命令行,CLion/VSCode/VSStudio插件等,检测规则还可以定制,重要的是免费开源,快去用起来吧,写出优雅的C++代码~

参考资料:

https://clang.llvm.org/extra/clang-tidy/

https://www.bilibili.com/video/av96166240/

 

责任编辑:武晓燕 来源: 程序喵大人
相关推荐

2022-03-11 12:14:43

CSS代码前端

2019-09-20 15:47:24

代码JavaScript副作用

2020-05-14 09:15:52

设计模式SOLID 原则JS

2021-12-07 08:16:34

React 前端 组件

2020-07-15 08:17:16

代码

2020-05-08 14:45:00

JS代码变量

2013-06-07 14:00:23

代码维护

2020-05-11 15:23:58

CQRS代码命令

2021-09-01 08:55:20

JavaScript代码开发

2021-11-30 10:20:24

JavaScript代码前端

2022-02-08 19:33:13

技巧代码格式

2022-02-17 10:05:21

CSS代码前端

2020-12-19 10:45:08

Python代码开发

2020-05-19 15:00:26

Bug代码语言

2021-12-13 14:37:37

React组件前端

2022-10-24 08:10:21

SQL代码业务

2019-06-24 10:26:15

代码程序注释

2015-09-28 10:49:59

代码程序员

2021-04-29 21:54:44

Python代码语言

2015-05-11 10:48:28

代码干净的代码越少越干净
点赞
收藏

51CTO技术栈公众号