Clang-Format格式化代码
安装
Linux
sudo apt-get install clang-format
windows
每每到这时候就越能感受到用 Linux 作为开发环境的优势,Windows 安装就稍显复杂了。
-
你可以选择安装完整的 LLVM,在
bin
目录可以看到clang-format.exe
。安装完后,将bin
目录添加到环境变量中。 -
你也可以只下载
clang-format.exe
,从LLVM Snapshot Builds下载安装包。在下载页面的底部。同样你需要将单独下载的文件加入到环境变量中。
使用
入门使用
Linux 可以直接命令行,使用以 LLVM 代码风格格式化main.cpp
, 结果直接写到main.cpp
clang g-format -i main.cpp -style=LLVM
进阶配置
如果每次编码都命令行执行一遍那也太麻烦了,而且每次修改也不止一个文件。最好的方式就是每次保存文件时自动格式化。比如 VSCode 已经内置了Clang-Format
稍作配置即可实现,接下来介绍几种常见 IDE 如何配置Clang-Format
。
VSCode
VSCode 最常用,因为内置了Clang-Format
也最容易配置。
- 安装
C/C++
插件,Ctrl+Shift+X
打开应用商店,搜索C/C++
找到下图插件,安装后会自动安装Clang-Format
程序,无需单独下载。默认安装路径为:
C:\Users\(你的用户名)\.vscode\extensions\ms-vscode.cpptools-1.7.1\LLVM\bin\clang-format.exe
。
- 打开设置页面(左下角齿轮 - 设置),搜索
format
,勾选Format On Save
,每次保存文件时自动格式化文档。下方的设置是决定每次格式化是整个文档,还是做过修改的内容。默认是file
,对整个文档进行格式化。
- 仍在设置页面搜索
Clang
,配置如下。.clang-format
文件最后详解。
- 效果图
QtCreator
- 安装
Beautifier
插件:帮助(Help
)-关于插件(About Plugins
)-Beautifier
勾选,重启 QtCreator。
- 工具(Tool)-
Beautifier
,配置如图。该配置,保存文档时自动格式化,并选择Clang-Format
作为格式化工具。
配置Clang-Format
程序路径,如果开头已经apt install
安装过,这里会自动补全。
Use predefined style
可以选择内置的一些代码风格,如LLVM
,Google
等。Use customized style
使用自定义的一些代码风格。点击添加(Add
)将配置文件粘贴进去即可,具体配置文件见最后。- 别忘了点击
OK
保存。
Eclipse
-
安装
cppstyle
插件:Help - Eclipse Marketplace - 搜索cppstyle
。 -
下载
cpplint
。
可以去github上下载cpplint的源码,下载完之后解压放到某个目录下。 -
在
Window
-Preferences
-C/C++
-CppStyle
页面把clang-format
的路径添加进去,然后把cpplint
的目录指向刚才下载的styleguide
目录下的cpplint/cpplint.py
就可以了。勾选下面的Enable cpplint
,Run clang-format on file save
,然后点击Apply and Close
保存修改并退出。如下图所示。
-
此时再保存代码,将会出现如下错误,因为我们还未给当前项目编写配置文件
.clang-format
。将最后一章提到的配置文件放到当前项目的下即可,程序会自动搜索。Cannot find .clang-format or _clang-format configuration file under any level parent directories of path. Clang-format will default to Google style.
配置简介
上文多次提到了.clang-format
配置文件,该文件决定了代码如何格式化,现在来介绍如何使用该文件。
导出.clang-format
文件
如果重新编写一份配置文件,需要考虑的东西太多,clang-format
内置了一些常见风格,我们可以根据已有的配置文件稍作修改,形成自己的代码风格。所以我们先导出一份内置的配置文件。
clang-format -style=可选格式名 -dump-config > .clang-format
# 可选格式最好写预设那那几个写最接近你想要的格式。比如我想要接近 Google C++ style 的。我就写-style=google
各个选项的含义
这里给出了配置的含义,感兴趣也可以查看官方文档,还提供了一些有案例,描述更清晰。
一些比较明显的代码分格区别
# 括号是分行,还是不分行,只有当 BreakBeforeBraces 设置为 Custom 时才有效
BraceWrapping:
AfterCaseLabel: true
# class 定义后面
AfterClass: true
# 控制语句后面
AfterControlStatement: true
AfterEnum: true
AfterFunction: true
AfterNamespace: true
AfterObjCDeclaration: true
AfterStruct: true
AfterUnion: true
AfterExternBlock: true
BeforeCatch: true
BeforeElse: true
# 缩进大括号,if else 语句后面的括号缩进
IndentBraces: false
SplitEmptyFunction: true
SplitEmptyRecord: true
SplitEmptyNamespace: true
BreakBeforeBinaryOperators: None
BreakBeforeBraces: Custom
# tab 宽度
TabWidth: 4
# 换行缩进字符数
IndentWidth: 4
# 宏定义对齐
AlignConsecutiveMacros: AcrossEmptyLinesAndComments
基于LLVM代码风格修改的个人使用版本:
---
Language: Cpp
# BasedOnStyle: LLVM
AccessModifierOffset: -2
AlignAfterOpenBracket: Align
# 宏定义对齐
AlignConsecutiveMacros: AcrossEmptyLinesAndComments
AlignConsecutiveAssignments: true
AlignConsecutiveDeclarations: true
AlignConsecutiveBitFields: true
AlignEscapedNewlines: Right
AlignOperands: true
AlignTrailingComments: true
AllowAllArgumentsOnNextLine: true
AllowAllConstructorInitializersOnNextLine: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowShortBlocksOnASingleLine: Never
AllowShortCaseLabelsOnASingleLine: false
# 是否允许短方法单行,只有一行的函数将不会分行,直接写在函数名后
AllowShortFunctionsOnASingleLine: false
AllowShortLambdasOnASingleLine: All
AllowShortIfStatementsOnASingleLine: Never
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: MultiLine
BinPackArguments: true
BinPackParameters: true
# 括号是分行,还是不分行,只有当 BreakBeforeBraces 设置为 Custom 时才有效
BraceWrapping:
AfterCaseLabel: true
# class 定义后面
AfterClass: true
# 控制语句后面
AfterControlStatement: true
AfterEnum: true
AfterFunction: true
AfterNamespace: true
AfterObjCDeclaration: true
AfterStruct: true
AfterUnion: true
AfterExternBlock: false
BeforeCatch: true
BeforeElse: true
# 缩进大括号
IndentBraces: false
SplitEmptyFunction: true
SplitEmptyRecord: true
SplitEmptyNamespace: true
BreakBeforeBinaryOperators: None
BreakBeforeBraces: Custom
BreakBeforeInheritanceComma: false
BreakInheritanceList: BeforeColon
BreakBeforeTernaryOperators: true
BreakConstructorInitializersBeforeComma: false
BreakConstructorInitializers: BeforeColon
BreakAfterJavaFieldAnnotations: false
BreakStringLiterals: true
ColumnLimit: 100
CommentPragmas: '^ IWYU pragma:'
CompactNamespaces: false
ConstructorInitializerAllOnOneLineOrOnePerLine: false
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
Cpp11BracedListStyle: true
DeriveLineEnding: true
DerivePointerAlignment: false
DisableFormat: false
ExperimentalAutoDetectBinPacking: false
FixNamespaceComments: true
ForEachMacros:
- foreach
- Q_FOREACH
- BOOST_FOREACH
IncludeBlocks: Preserve
IncludeCategories:
- Regex: '^"(llvm|llvm-c|clang|clang-c)/'
Priority: 2
SortPriority: 0
- Regex: '^(<|"(gtest|gmock|isl|json)/)'
Priority: 3
SortPriority: 0
- Regex: '.*'
Priority: 1
SortPriority: 0
IncludeIsMainRegex: '(Test)?$'
IncludeIsMainSourceRegex: ''
IndentCaseLabels: false
IndentGotoLabels: true
IndentPPDirectives: None
# 换行缩进字符数
IndentWidth: 4
IndentWrappedFunctionNames: false
JavaScriptQuotes: Leave
JavaScriptWrapImports: true
KeepEmptyLinesAtTheStartOfBlocks: true
MacroBlockBegin: ''
MacroBlockEnd: ''
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
ObjCBinPackProtocolList: Auto
ObjCBlockIndentWidth: 0
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: true
PenaltyBreakAssignment: 2
PenaltyBreakBeforeFirstCallParameter: 19
PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120
PenaltyBreakString: 1000
PenaltyBreakTemplateDeclaration: 10
PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 60
PointerAlignment: Right
ReflowComments: true
SortIncludes: true
SortUsingDeclarations: true
SpaceAfterCStyleCast: false
SpaceAfterLogicalNot: false
SpaceAfterTemplateKeyword: true
SpaceBeforeAssignmentOperators: true
SpaceBeforeCpp11BracedList: false
SpaceBeforeCtorInitializerColon: true
SpaceBeforeInheritanceColon: true
SpaceBeforeParens: ControlStatements
SpaceBeforeRangeBasedForLoopColon: true
SpaceInEmptyBlock: false
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 1
SpacesInAngles: false
SpacesInConditionalStatement: false
SpacesInContainerLiterals: true
SpacesInCStyleCastParentheses: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
SpaceBeforeSquareBrackets: false
Standard: Latest
StatementMacros:
- Q_UNUSED
- QT_REQUIRE_VERSION
TabWidth: 8
UseCRLF: false
UseTab: Never
...
格式化最新的commit代码
clang-format
还提供一个clang-format-diff.py
脚本,用来格式化patch
,code review
提交代码前,跑一遍下面的代码。
// 格式化最新的 commit,并直接在原文件上修改
git diff -U0 HEAD^ | clang-format-diff.py -i -p1
常见问题
如何看懂官方文档并编写配置文件
官方文档里有各种设置的示例代码,即使不知道想要的格式化是哪个配置参数,翻一翻官方文档是示例大概率能找到。那么找到了想要的配置参数,如何在文件里配置呢?
以宏定义对齐为例。我们想要宏定义的值保持对齐的状态,如下一节图片所示。可以翻一遍官方文档,可以发现这个示例代码对应的参数可能是我们想要的,AlignConsecutiveMacros
翻译为对齐连续的宏定义。那应该八九不离十了。
找到了参数如何编写配置文件呢?可以继续看这个参数下面的更多示例,每一个示例都对应一个配置可能值Possible values
。
-
ACS_None
(in configuration:None
)
Do not align macro definitions on consecutive lines.
ACS_None
为这个配置的缩写,None
表示在配置文件里的值。该配置表示不对宏定义进行对齐操作,在配置文件里可以添加如下:AlignConsecutiveMacros: None
-
ACS_Consecutive
(in configuration:Consecutive
)
Align macro definitions on consecutive lines. This will result in formattings like:#define SHORT_NAME 42 #define LONGER_NAME 0x007f #define EVEN_LONGER_NAME (2) #define foo(x) (x * x) /* some comment */ #define bar(y, z) (y + z)
ACS_Consecutive
为这个配置的缩写,Consecutive
表示在配置文件里的值。该配置表示对连续的宏定义进行对齐,在配置文件里可以添加如下:AlignConsecutiveMacros: Consecutive
宏定义对齐失效
# 宏定义对齐
AlignConsecutiveMacros: AcrossEmptyLinesAndComments
使用宏定义对齐更详细的配置,可以参考官方文档。使用该配置一定要使用等宽的字体,否则配置生效但是显示不正确。
比如我是用微软雅黑字体作为编码字体,因为该字体每个字符不等宽,导致格式化正确,但是显示不正确。
如果将字体换位等宽字体如常用的Consolas,就可以正常显示。