最近项目快完成了,老板说交出来的必须通过代码规范扫描,好吧,没办法去研究了下cpplint,然后就是,一个cpp文件给我报了三百多个错!
没办法,改吧。
先说一下cpplint,这是一个用于检查C++代码风格的工具,它可以帮助我们自动化地检查代码,发现潜在的编码问题,确保代码风格的一致性和规范性,提高代码质量。cpplint遵循Google的C++编码规范,通过静态分析代码来检查潜在的问题,如命名规范、格式、内存管理等。
我们可以把cpplint嵌入到VS中使用,方便对每个类进行编码规范检查和修改,具体的安装使用方式大家可以参考一下这篇文章:
下面将针对在使用中cpplint报出的一系列问题解释其报错原因并给出修改建议。
目录:
1、error cpplint: [whitespace/indent] private: should be indented +1 space inside class xxx
2、error cpplint: [whitespace/tab] Tab found; better to use spaces [1]
5、error cpplint: [runtime/indentation_namespace] Do not indent within a namespace
6、error cpplint: [whitespace/braces] { should almost always be at the end of the previous line
7、error cpplint: [readability/namespace] Namespace should be terminated with "// namespace xxx"
8、error cpplint: [whitespace/line_length] Lines should be <= 180 characters long
13、error cpplint: [build/include_subdir] Include the directory when naming header files
14、error cpplint: [whitespace/forcolon] Missing space around colon in range-based for loop
1、error cpplint: [whitespace/indent] private: should be indented +1 space inside class xxx
报错原因:指出在类 xxx 中,private:
访问修饰符的缩进不符合预期的规范
修改建议:根据 Google C++ 编程风格指南,类中的访问修饰符(如 public:
、protected:
、private:
)应当比类名多缩进一个空格。
示例:
错误方式:
class Widget {
private:
int some;
// ...
};
正确方式:
class Widget {
public:
// 如果类中有 public 部分,它应该这样缩进
private:
int some;
// ...
};
注意,如果类中没有 public
或 protected
部分,只有 private
部分,我们仍然需要确保 private:
的缩进是正确的。此外,如果我们的代码中有多个访问修饰符,每一个都应该遵循相同的缩进规则。
2、error cpplint: [whitespace/tab] Tab found; better to use spaces [1]
报错原因:表示在文件 xxx.h
的第 xx 行发现了一个制表符(Tab),而 cpplint
工具建议我们使用空格来代替制表符。
修改建议:在 Google C++ 编程风格指南中,推荐使用空格而不是制表符来进行缩进,因为不同的编辑器或IDE可能对制表符的显示宽度有不同的设置,这可能导致代码在不同环境中看起来不整齐。使用空格进行缩进则更具一致性和可读性。
示例:
1、打开 xxx |
2、转到第 xx 行。 |
3、检查该行或附近的代码,找到制表符(Tab)。在大多数文本编辑器和IDE中,制表符通常显示为一条长条或箭头,而空格则显示为空白。 |
4、将制表符替换为适当数量的空格。通常,一个制表符应该被替换为 4 个空格(但这也取决于你的具体项目或团队的编码规范)。 |
5、保存文件并重新运行 cpplint 检查。 |
3、error cpplint: [runtime/references] Is this a non-const reference? If so, make const or use a pointer: QString& xxx
报错原因:对于函数参数QString& xxx
应该使用const
引用
修改建议:在Google的C++编程风格指南中,通常建议对于函数参数,如果函数内部不会修改这个参数,那么应该使用const
引用,而不是非const
引用。这有助于保证函数不会意外地修改传入的参数,从而提高代码的可读性和可维护性。
示例:
QVector<int> xxx(QTextEdit *xxx, const QString& xxx);
在大多数情况下,将字符串参数作为const
引用传递是一个好习惯,因为它可以避免不必要的字符串拷贝,并且清晰地表明函数不会修改这个参数。
4、error cpplint: [whitespace/end_of_line] Line ends in whitespace. Consider deleting these extra spaces.
报错原因:错误指出在xxx.h
文件的第xx行末尾存在多余的空白字符(通常是空格)。
修改建议:按照cpplint
(以及许多其他编程规范)的建议,代码行的末尾不应该包含多余的空白字符,因为这可能会影响代码的可读性和可维护性,尤其是在使用版本控制系统(如Git)时,可能会导致不必要的差异。
示例:
1、打开xxx |
2、转到第xx行。 |
3、删除该行末尾的所有空白字符(通常是空格或制表符)。 |
4、保存文件。 |
5、error cpplint: [runtime/indentation_namespace] Do not indent within a namespace
报错原因:这个错误是关于命名空间(namespace)内的缩进问题的。错误指出不应该在命名空间内部进行额外的缩进。
修改建议:在C++中,通常命名空间的开始和结束大括号 {
和 }
不需要额外的缩进,除非你有特定的代码风格要求。也就是说,namespace里class应该顶格而不需要额外缩进。
示例:
错误示例:
// 错误的缩进方式
namespace MyNamespace {
// 这里有额外的缩进
class MyClass {
// ...
};
// 这里也有额外的缩进
}
正确示例:
// 正确的缩进方式
namespace MyNamespace {
class MyClass {
// ...
};
}
6、error cpplint: [whitespace/braces] { should almost always be at the end of the previous line
报错原因:这个错误意味着我们的左大括号 {
没有放在其对应语句的末尾,而是放在了一个新行上。
修改建议:按照cpplint
(和许多C++代码风格指南)的建议,左大括号应该放在其对应语句(如类、函数、命名空间等)的末尾,而不是放在新的一行。
示例:
错误示例:
// 错误的方式
class MyClass
{
// ...
};
正确示例:
// 正确的方式
class MyClass {
// ...
};
7、error cpplint: [readability/namespace] Namespace should be terminated with "// namespace xxx"
报错原因:这个错误建议在命名空间的末尾添加一个注释来明确命名空间的结束。
修改建议:虽然这不是所有代码风格都要求的,但cpplint
认为这是提高可读性的一个好习惯。
示例:
错误方式:
// 错误的方式
namespace CalculatePlugin {
// ...
}
正确方式:
// 正确的方式
namespace CalculatePlugin {
// ...
} // namespace xxx
8、error cpplint: [whitespace/line_length] Lines should be <= 180 characters long
报错原因:错误指出在文件xxx.h
的第 xx 行,代码行的长度超过了建议的最大字符数限制(180个字符)。
修改建议:
1、拆分长行: |
2、使用代码格式化工具: |
3、调整 cpplint 的配置: |
4、注释掉或禁用该检查: |
示例:拆分长行:检查第 xx 行,看看是否可以将它拆分成多个较短的行。
错误方式:
// 原始的长行
void Some(int param1, int param2, int param3, /* ... 其他参数 ... */);
正确方式:
// 拆分后的多行
void Some(
int param1,
int param2,
int param3,
// ... 其他参数 ...
);
9、error cpplint: [build/header_guard] #ifndef header guard has wrong style, please use: SRC_XXX_XXX_H_
报错原因: cpplint 期望我们使用特定的命名约定来定义头文件保护宏(header guard)。
修改建议:在这个情况下,它希望我们使用大写字母,并且以项目的目录结构为基础来命名。所以需要将我们的 #ifndef
和 #define
指令修改为符合格式的宏定义:
示例:
#ifndef SRC_XXX_XXX_H_
#define SRC_XXX_XXX_H_
// ... 头文件内容 ...
#endif // SRC_XXX_XXX_H_
10、error cpplint: [whitespace/ending_newline] Could not find a newline character at the end of the file
报错原因:这个错误说明文件的最后一行缺少换行符。cpplint 希望文件末尾有一个换行符,即使这个换行符在文件打开时看起来是“空”的。
修改建议:在文件末尾添加一个新行。我们可以通过许多文本编辑器或 IDE 的“保存”功能来自动完成这一步骤,因为很多这样的工具会在保存文件时自动添加缺失的换行符。
11、error cpplint: [legal/copyright] No copyright message found. You should have a line: "Copyright [year] <Copyright Owner>
报错原因:这个错误表明 cpplint
工具在 xxx.h
文件中没有找到版权信息。根据 Google 的 C++ 编程风格指南,建议每个文件都应该包含一个版权声明。
修改建议:需要在文件的顶部添加一条版权信息。通常,版权信息会包含版权声明的年份和版权所有者。
示例:版权声明的格式
// Copyright 2023 <你的版权所有者>
//
// Licensed under the <某种许可协议> (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// <许可协议的URL>
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// 以下是你的文件内容...
将 <你的版权所有者>
替换为你的组织或个人的名称,<某种许可协议>
替换为代码所使用的许可协议(例如 Apache 2.0、MIT、BSD 等),并将 <许可协议的URL>
替换为相应的网址(如果可用)即可。
12、error cpplint: [build/include_order] Found C system header after other header. Should be: xxx.h, c system, c++ system, other.
报错原因:这个错误指出在 xxx.cpp
文件的第 x 行,包含了一个 C 系统头文件(通常是那些没有以 .hpp
或不带扩展名,且以 < >
包围的头文件,如 <stdio.h>
),但它出现在其他非系统头文件(可能是项目中的头文件,如 xxx.h
)之后。
修改建议:根据 cpplint 的规则,建议的头文件包含顺序应该是:
1、项目自身的头文件(通常使用 |
2、C 系统头文件(使用 < > 包围)。 |
3、C++ 系统头文件(同样使用 < > 包围)。 |
4、其他头文件。 |
示例:
// 先包含项目自身的头文件
#include "xxx.h"
// 然后是 C 系统头文件
#include <stdio.h> // 举例,根据代码实际需要替换或添加
// 然后是 C++ 系统头文件(如果有的话)
// #include <...>
// 最后是其他头文件(如果有的话)
// #include "..."
// ... 代码 ...
13、error cpplint: [build/include_subdir] Include the directory when naming header files
报错原因:这个 cpplint 错误是关于在包含(include)头文件时没有包含目录名称的问题。
修改建议:在 C++ 中,当头文件与源文件位于不同的目录时,通常需要在包含时指定相对路径或绝对路径。然而,cpplint 建议即使头文件和源文件在同一个目录下,也应该在包含时明确指定目录名(即使目录名是当前目录)。
这个规则是为了保持代码的可读性和可维护性,因为当项目结构发生变化时,使用目录名称可以避免路径解析问题。
示例:假设头文件 xxx.h
与 xxx.cpp
在同一个目录下(即 yyy 目录下),应该这样包含头文件:
在.cpp文件下
#include "yyy/xxx.h"
错误方式:
#include "xxx1.h"
#include "xxx2.h"
正确方式:
#include "yyy/xxx1.h"
#include "yyy/xxx2.h"
当然,如果头文件实际上位于不同的目录,那需要将路径修改为正确的相对路径或绝对路径。
继续补充:
14、error cpplint: [whitespace/forcolon] Missing space around colon in range-based for loop
报错原因:指出在文件 xxx.cpp
的第 xxx 行,存在一个范围基于 for 循环(range-based for loop)中冒号(:)周围有空格缺失问题。
修改建议:在冒号(:)的两侧各添加一个空格,使代码符合 cpplint
的检查要求。
示例:
错误方式:
for (const auto& item:connn) {
// ... 循环体 ...
}
正确示例:
for (const auto& item : connn) {
// ... 循环体 ...
}
15、error cpplint: [runtime/explicit] Constructors callable with one argument should be marked explicit.
报错原因:指出在文件 xxx.h
的第 xx 行,存在一个构造函数,它可以被只带有一个参数的调用所隐式调用,但是没有被标记为 explicit
修改建议:在 C++ 中,如果一个构造函数只接受一个参数,并且没有被标记为 explicit
,那么这个构造函数可以隐式地用于类型转换。这可能会导致一些非预期的行为,特别是当我们不希望发生这种隐式转换时。
为了解决这个问题,需要在相应的构造函数声明前添加 explicit
关键字。
示例:
错误方式:
// 错误方式(可能导致隐式转换)
class 111base{
public:
111base(int value); // 缺少 explicit 关键字
// ... 其他成员函数和成员变量 ...
};
正确方式:
// 正确示例(显式构造函数,禁止隐式转换)
class 111base{
public:
explicit 111base(int value); // 添加了 explicit 关键字
// ... 其他成员函数和成员变量 ...
};
以上也仅仅是列出我遇到的部分建议,后续会随时补充。
都看到这里了,点个赞再走呗朋友~
加油吧,预祝大家变得更强!
点赞!点赞!点赞!