代码风格和语言版本
为了实现外观一致的产品,我们将遵循各语言的外部(如果可能)定义的样式指南。对于包布局或文档布局等其他事项,我们将需要制定自己的指南,借鉴当前流行的样式。
此外,开发人员应尽可能使用集成工具来检查编辑器中是否遵循了这些指南。例如,每个人都应该在其编辑器中内置一个 PEP8 检查器,以减少与样式相关的审查迭代。
此外,尽可能地,软件包应在其单元测试中检查样式,以帮助自动检测样式问题(参见 ament_lint_auto)。
C
样式
我们将使用 Python的PEP7 作为我们的C代码风格指南,并进行一些修改和添加:
我们将以C99为目标,因为我们不需要支持C89(如PEP7建议)
理由:除其他外,它允许我们同时使用
//
和/* */
样式的注释解释:C99现在几乎无处不在
允许使用C++风格的``//``注释
(可选) 总是将文字直接量放在比较操作符的左边,例如使用``0 == ret``而不是``ret == 0``
解释:
ret == 0``容易出错为``ret = 0
可选的,因为当使用``-Wall``(或等效选项)时,现代编译器会在发生此情况时给出警告
以下所有修改仅适用于非编写Python模块的情况:
不要将``Py_``作为所有内容的前缀
而是使用包名的驼峰命名法或其他适当的前缀
关于文档字符串的内容不适用
我们可以使用 pep7 Python 模块进行风格检查。编辑器集成似乎很简单,我们可能需要更详细地研究C语言的自动检查。
C++
样式
我们将使用 Google C++ Style Guide,并进行一些修改:
行长度
我们的最大行长度为 100 个字符。
文件扩展名
头文件应使用 .hpp 扩展名。
理由:允许工具确定文件的内容,无论是 C++ 还是 C。
实现文件应使用 .cpp 扩展名。
理由:允许工具确定文件的内容,无论是 C++ 还是 C。
变量命名
对于全局变量,请使用小写字母和下划线,并在前面加上一个空格``g_``
原因:在整个项目中保持变量命名大小写一致
原因:一目了然地确定变量的作用域
跨语言保持一致性
函数和方法命名
谷歌样式指南要求使用``CamelCase``,但C++标准库的样式``snake_case``也是允许的
理由:ROS 2核心包目前使用``snake_case``
原因:可能是历史遗漏或未经linter检查的个人偏好
不更改的原因:追溯性更改会造成过大的干扰
其他考虑因素:
cpplint.py
不检查此情况(除非通过审查进行强制执行,否则很难实施)snake_case
可以实现跨语言更一致的结果
具体指导:
对于现有项目,请优先采用现有的风格
对于新项目,两种风格都可以接受,但建议优先选择与相关现有项目相匹配的风格
最终决策由开发人员自行决定
特殊情况,如函数指针、可调用类型等,可能需要打破规则
注意,类应该仍然默认使用“CamelCase”
访问控制
放宽对所有类成员必须私有的要求,从而需要访问器
解释:这对用户API设计来说过于限制性。
解释:我们应该更倾向于私有成员,只有在需要时才将它们设置为公开。
解释:在选择允许直接成员访问之前,我们应该考虑使用访问器。
解释:除了对我们方便之外,我们应该有一个充分的理由来允许直接成员访问。
异常
允许使用异常
解释:这是一个全新的代码库,所以我们不适用于传统的论点
解释:对于面向用户的 API,使用异常更符合 C++ 的习惯用法
析构函数中应明确避免异常
如果我们打算在C中包装所得到的API,则应考虑避免异常
理由:这将使在C中进行包装更容易
理由:我们打算在C中包装的代码大多数不会使用异常
Boost
除非绝对必要,应避免使用Boost。
评论和文档注释
类隐私关键字
嵌套模板
永远不要在嵌套模板中添加空格
更喜欢使用``set<list<string>>``(C++11特性),而不是``set<list<string> >``或``set< list<string> >``
花括号的风格选择
对于
function
、class
、enum
和struct
的定义,使用空格后的开放花括号,但是对于if
、else
、while
、for
等语句使用相邻的花括号...例外情况:当
if``(或 ``while
等)条件太长需要换行时,使用开放花括号(即不相邻的形式)。
当函数调用不能在一行内容纳时,在开放的括号处换行(不在参数之间),并在下一行以2个空格缩进开始。对于更多的参数,继续使用2个空格缩进的格式进行下一行。注意,这一点在 Google 风格指南 上有内部矛盾。
对于太长无法放在一行的``if``(以及``while``等)条件同样适用。
示例
这是可以的:
int main(int argc, char **argv)
{
if (condition) {
return 0;
} else {
return 1;
}
}
if (this && that || both) {
...
}
// Long condition; open brace
if (
this && that || both && this && that || both && this && that || both && this && that)
{
...
}
// Short function call
call_func(foo, bar);
// Long function call; wrap at the open parenthesis
call_func(
foo, bar, foo, bar, foo, bar, foo, bar, foo, bar, foo, bar, foo, bar, foo, bar, foo, bar,
foo, bar, foo, bar, foo, bar, foo, bar, foo, bar, foo, bar, foo, bar, foo, bar, foo, bar);
// Very long function argument; separate it for readability
call_func(
bang,
fooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo,
bar, bat);
这是**不**可以的:
int main(int argc, char **argv) {
return 0;
}
if (this &&
that ||
both) {
...
}
使用大括号而不是过多的缩进,例如用于区分构造函数中的代码和构造函数初始化列表
这是可以的:
ReturnType LongClassName::ReallyReallyReallyLongFunctionName(
Type par_name1, // 2 space indent
Type par_name2,
Type par_name3)
{
DoSomething(); // 2 space indent
...
}
MyClass::MyClass(int var)
: some_var_(var),
some_other_var_(var + 1)
{
...
DoSomething();
...
}
这是 不正确的,甚至很奇怪(Google 的方式?):
ReturnType LongClassName::ReallyReallyReallyLongFunctionName(
Type par_name1, // 4 space indent
Type par_name2,
Type par_name3) {
DoSomething(); // 2 space indent
...
}
MyClass::MyClass(int var)
: some_var_(var), // 4 space indent
some_other_var_(var + 1) { // lined up
...
DoSomething();
...
}
代码检查工具
我们使用 Google 的 cpplint.py 和 uncrustify 的组合来检查这些风格。
我们提供带有自定义配置的命令行工具:
一些格式化工具,例如ament_uncrustify和ament_clang_format,支持“--reformat”选项以直接应用更改。
我们还运行其他工具来尽可能检测和消除警告。以下是我们在所有软件包上尝试做的一些额外工作的非详尽列表:
使用编译器标志,如“-Wall -Wextra -Wpedantic”。
运行静态代码分析工具,例如cppcheck,我们已将其集成到`ament_cppcheck <https://github.com/ament/ament_lint/blob/humble/ament_cppcheck/doc/index.rst>`__中。
Python
Markdown / reStructured Text / docblocks
样式
以下用于格式化文本的规则旨在提高可读性和版本控制。
[.md, .rst only] 每个章节标题前应有一个空行,后面也应有一个空行。
原因:这有助于在浏览文档时快速获取结构概览。
[.rst only] 在 reStructured Text 中,标题应遵循 Sphinx 风格指南 中描述的层次结构:
#
上方加线(仅一次,用于文档标题)*
上方加线=
-
^
"
解释:保持一致的层次结构有助于在查看文档时快速了解嵌套层级。
[仅限.md格式] 在Markdown中,标题应遵循`Markdown语法文档<https://daringfireball.net/projects/markdown/syntax#header>`__中描述的ATX样式
ATX样式的标题使用1-6个井号字符(
#
)在行首表示标题级别1-6应在井号和标题之间使用一个空格(例如
# 标题1
)以便更容易进行视觉分隔ATX样式的偏好来自于`Google Markdown样式指南<https://github.com/google/styleguide/blob/gh-pages/docguide/style.md#atx-style-headings>`__
原理: ATX 样式的标题更容易搜索和维护,并且使得前两个标题级别与其他级别保持一致。
[任意] 每个句子必须从新的一行开始。
原理: 对于较长的段落,一开始的单个更改会导致差异难以阅读,因为它会一直延续到整个段落。
[任意] 每个句子可以选择性地换行,以保持每行短小。
[任意] 行末不应有任何空白。
[仅限 .md、.rst] 代码块前后必须有空行。
原因:只有在有围栏代码块的直接前后空格才有意义。遵循这些指示将确保高亮显示正常且一致。
[仅限 .md、.rst] 代码块应指定语法(例如
bash
)。