VS Code 中有个微软开发的 C/C++ 扩展。这个扩展可以实现代码高亮、库识别,当然也包括本文要提到的格式化代码(Format code)。也就是自动把你的代码调整成某一标准格式,这不光方便自己查看,在很多大项目中,提交之前都需要按照对应标准格式化代码(当然他们也会有自己的格式化程序,但是这里不讨论这个)。
但是这个格式化可能并不是你我想要的,当然你也可以自己花时间去写 ClangFormat 的配置文件(因为 VS Code 是用的 ClangFormat),但是大部分人并不需要这么深入,只用调整几个部分的参数,所以配置文件的方法放到最后说。
设置
首先我们要知道在哪里更改设置,在扩展设置里面,看“Formatting”部分。
这里你也可以看到有三种设置格式化代码的方法:
- 预设:
Visual Studio
(默认是这个),LLVM
,Google
,Chromium
,Mozilla
,WebKit
,Microsoft
,GNU
和none
。 - 键值对:这个方案是用
{key: value, ...}
的方法调整一些参数,相当于上一种方法的细致版。 .clang-format
配置文件:如果没找到配置文件,才使用 VS Code 设置里的方式。
下面介绍一下这三种方法的区别和细节。
代码
演示用的代码是下面这段混乱不堪的代码。这段代码首先简短,其次可以比较明显的看出来变化。
#include <iostream>
int main() {
for (int i = 0; i < 5; ++i) {std::cout << i << " ";
}return 0;
}
预设
这里我只展示了几种,也是你大概率会选择的。其他的你可以自己试试看,刚好练习一下。
Visual Studio
这个默认值是 Visual Studio
。
格式化的时候,右键点击下面的这个“Format Document”,就会格式化整个文档:
效果如下:
#include <iostream>
int main()
{
for (int i = 0; i < 5; ++i)
{
std::cout << i << " ";
}
return 0;
}
你可以看到缩进 4 格、换行之类的格式化良好,大括号放在下一行了。
大括号在下一行的风格叫做 Allman 风格(Clang Format 选择的是这个名字)或者 BSD 风格。
LLVM
接下来我们使用LLVM
:
#include <iostream>
int main() {
for (int i = 0; i < 5; ++i) {
std::cout << i << " ";
}
return 0;
}
你会发现虽然大括号在行尾,但是缩进只有 1 格。
虽然 clang 及其额外工具是 LLVM 开发的,但是 LLVM 有自己格式化配置文件,所以也不推荐用这个。
GNU
GNU
的风格对于很多人来说较为另类:
#include <iostream>
int
main ()
{
for (int i = 0; i < 5; ++i)
{
std::cout << i << " ";
}
return 0;
}
你可以看到虽然缩进变成了 2 格,大括号也在下一行,但是函数也分成几行写了。
关于缩进
这里多说几句关于缩进的事情。虽然前面就该提了,但是 GNU 和 Linux 的关系更加密切,而且 VS Code 并没有 Linux 相关的预设,所以就放在这里说了:
- 对绝大部分语言来说,缩进(有的叫Tab)在 2 和 4 的时候可读性最好。
- 缩进(Indent)和 Tab 虽然这两个是两个东西,但是在某种意义上他们俩可以互相替换。要理解这个概念你要搞清楚什么叫 tab,如果你感兴趣可以看看我的另一篇博客 tab stop(制表符)是什么?- ZhongUncle’s CSDN
- Linus 本人认为缩进应该是 8 格,4 和 2 是异教徒,非常古典的想法了(Vim 默认就是 8 格)。在 Linux 内核的仓库root/Documentation/process/coding-style.rst中有这样一段话:
Tabs are 8 characters, and thus indentations are also 8 characters. There are heretic movements that try to make indentations 4 (or even 2!) characters deep, and that is akin to trying to define the value of PI to be 3.
制表符是 8 个字符,因此缩进也是 8 个字符。有异端运动试图把缩进改成 4 格(甚至 2 格!)字符很深,这类似于试图将 PI 的值定义为是 3。
- 3 格其实也不错,后面我们可以看看。(毕竟 4 太多,2 太少)
Google
这个预设和LLVM
差不多:
#include <iostream>
int main() {
for (int i = 0; i < 5; ++i) {
std::cout << i << " ";
}
return 0;
}
好了,预设就讲到这里。
键值对
它扩展设置的介绍中,给了一个参考的键值对:
{ BasedOnStyle: LLVM, UseTab: Never, IndentWidth: 4, TabWidth: 4, BreakBeforeBraces: Allman, AllowShortIfStatementsOnASingleLine: false, IndentCaseLabels: false, ColumnLimit: 0, AccessModifierOffset: -4, NamespaceIndentation: All, FixNamespaceComments: false }
由于它是单行的,这里不好解释,所以我们对它也格式化一下:
{
BasedOnStyle: LLVM,
UseTab: Never,
IndentWidth: 4,
TabWidth: 4,
BreakBeforeBraces: Allman,
AllowShortIfStatementsOnASingleLine: false,
IndentCaseLabels: false,
ColumnLimit: 0,
AccessModifierOffset: -4,
NamespaceIndentation: All,
FixNamespaceComments: false
}
可以看到他是基于某一种预设进行修改的。这里我们先使用这个例子看看:
#include <iostream>
int main()
{
for (int i = 0; i < 5; ++i)
{
std::cout << i << " ";
}
return 0;
}
可以看到,相比较LLVM
预设来说,缩进改成了 4 格。也就是这部分实现的:
IndentWidth: 4,
TabWidth: 4,
比如说我们想将大括号改成行尾,那么可以将BreakBeforeBraces
改成Attach
,如下:
BreakBeforeBraces: Attach,
那么可以看到下面这样,非常不错:
#include <iostream>
int main() {
for (int i = 0; i < 5; ++i) {
std::cout << i << " ";
}
return 0;
}
好了,关于这部分的介绍就到这里,因为我不想当文档的搬运工,请你自己去看官方文档 Clang-Format Style Options,里面对每个设置都有详细的介绍。
.clang-format
配置文件
首先第一步,先在项目根目录下创建.clang-format
文件(.clang-format
使用 YAML 格式):
.clang-format
配置文件的内容就是键值对方法的另一种样式,二者很像,比如我们在.clang-format
配置文件中写入:
---
Language: Cpp
BasedOnStyle: LLVM
UseTab: Never
IndentWidth: 3
TabWidth: 3
BreakBeforeBraces: Attach
AllowShortIfStatementsOnASingleLine: false
IndentCaseLabels: false
ColumnLimit: 0
AccessModifierOffset: -4
NamespaceIndentation: All
FixNamespaceComments: false
---
然后格式化,就会生成下面这样的(注意这里的缩进是 3 格):
#include <iostream>
int main() {
for (int i = 0; i < 5; ++i) {
std::cout << i << " ";
}
return 0;
}
你可能也注意到了,这个配置文件中可以单独设置不同语言的格式化。比如官方中给出的:
---
Language: Cpp
# Force pointers to the type for C++.
DerivePointerAlignment: false
PointerAlignment: Left
---
Language: JavaScript
# Use 100 columns for JS.
ColumnLimit: 100
---
这对于大项目来说太方便了。
当然它能使用的设置不止这些,这就需要你去看官方文档了。
希望能帮到有需要的人~
参考资料
Clang-Format Style Options - Clang 21.0.0git documentation:这个是核心资料/文档,因为 VS Code 就是单纯用了 ClangFormat。
GNU coding standards - GNU Project
Linux kernel coding style - The Linux Kernel
GNU 和 Linux 内核的代码样式文档,个人比较推荐后者。虽然 GNU 和 Linux 是相爱相杀的两个项目,GNU 的贡献更大,我也喜欢叫 GNU/Linux,但是不得不说,这一次,GNU 的文档写的不太行。
GNU 的编码样式标准太长了,而且对新手来说有点难懂。Linux 这个文档中,给出了对应的例子和建议。正如 Linux 文档中,Linus 说的一句话:
First off, I’d suggest printing out a copy of the GNU coding standards, and NOT read it. Burn them, it’s a great symbolic gesture.
首先,我建议打印一份 GNU 编码标准, 但不要阅读它。烧掉它们,这是一个很棒的象征性姿势。
顺道一提,本文引用的两句 Linus 说的话几乎就在一起:
编码风格是多种多样的,不同项目为了便捷也会使用不同的编码风格,这个没有谁高级谁低级的说法。像 Google、Apple 之类的大公司也有自己的编码风格。但是如果你让我推荐一篇来读,我推荐 Linux 这个,因为它解释和例子都非常不错。其他的属于你会了再看,一看就懂,你不会那就慢了。
ClangFormat - Clang 21.0.0git documentation:ClangFormat 的官方文档,里面介绍一下结构和clang-format
命令使用。
Lightning Talk: How Far Should You Indent Your Code? - The Number Of The Counting - Dave Steffen - CppCon:这个视频介绍了一下缩进的事情,虽然就几分钟但是蛮有意思的。比如其中的这张图。