测试clang-format的格式化效果
我自己写的业余框架已告一段落,主体功能已完成,剩下的就是优化。第一个要优化的,就是代码格式。我一直是用编辑器写代码的,从之前的UltraEdit到notepad++到sublime text,再到现在的VS Code。由于代码都是我一个人写,风格也比较统一,虽然说不上美观,但至少说得过去。但寻思着以后万一有人要用这代码,总得有个较为通用的代码风格才行,而且我也不太可能去人工约束别人怎么写,那就用工具吧。
C++不像Java、C#、TypeScript这些语言,他们都有较为通用的代码风格标准,比较通用的IDE,基本是自带代码格式化,因此整体上来说比较容易统一。但C++就没有,比如我在公司是用Visual Studio,在家有时候用的VS Code,有时候用的Qt。现在流行的C++代码格式化工具,大概有3个:clang-format、uncrustify、astyle。
clang-format是随LLVM项目而来的后起之秀,也是这次测试的重点。原因是它的开发现在是最活跃的,格式化选项是最多的,集成也是最多的(VS2017以后有集成,VS Code有插件,Qt在新版本中已经集成)。我花了点时间,尝试了解clang-format的配置,并做了些测试。
/* 测试clang-format格式化效果
*/ class Test
{
// 对齐这个public修饰符 AccessModifierOffset: -2
public:
}; // 括号断行后参数对齐方式 AlignAfterOpenBracket
void ttttttt(int aaaaaaa, int bbbbbbbbb,int ccccccccc,int ddddddddd, int eeeeeeeeeeeeeee, int ffffffffffffffffffffffffffffffff)
{
}
// TODO: 不能实现下面的对齐方式
// 1. 下一行长度大于上一行
// 2. 换行缩进为4格
//
void ttttttt(int aaaaaaa, int bbbbbbbbb,int ccccccccc,
int ddddddddd, int eeeeeeeeeeeeeee, int ffffffffffffffffffffffffffffffff)
{
} // 赋值时等号对齐 AlignConsecutiveAssignments
int aaaaaaa = ;
int b = ;
int ccccc = ; // 变量名左对齐,应该和上面的冲突 AlignConsecutiveDeclarations
int aaaa = ;
float b = ;
std::string ccc = ; // 宏对齐 AlignConsecutiveMacros
#define SHORT_NAME 42
#define LONGER_NAME 0x007f
#define EVEN_LONGER_NAME (2)
#define foo(x) (x * x)
#define bar(y, z) (y + z) // 断行符的对齐 AlignEscapedNewlines
#define A \
int aaaa; \
int b; \
int dddddddddd // 运算变量对齐 AlignOperands
int sum = aaaaaaaaaaa + bbbbbbbbbb
+ ccccccccccccccccccc + ddddddddddddddd + eeeeeeeeeee + fff; // 是否对齐行尾注释 AlignTrailingComments
int x; // test xxxxxxxx
int yyyyyyyyyyyyy; // test yyyyyyyyy
int zzzz; // test zzzzzzz // 调用函数时,参数的断行方式 AllowAllArgumentsOnNextLine
looooooooooooooooooooooooooooooooooooooooooooooong_call(aaaaaaaaaa,bbbbbbbb,cccccccc); // 构造函数初始化列表断行方式 AllowAllConstructorInitializersOnNextLine
class LongInitializers
{
public:
LongInitializers(): aaaaaaaaaaaaaaaaa(), bbbbbbbbbbbbbbbbbb(), ccccccccccccc()
{
}
}; // 函数声明时参数的断行方式 AllowAllParametersOfDeclarationOnNextLine
// 上面的AlignAfterOpenBracket优先级更高,会影响这个
int ddddddddddddddddddddddddddddddddddddddddd(int aaaaaa, int bbbbbbb,int cccccccccccc); // 是否把简短的代码合并成一行 AllowShortBlocksOnASingleLine
// 这个没生效,而且和文档也对不上了。文档有好几个值,配置只接受 true flase
if (a > b)
a++;
while (true)
{
a ++;
b ++;
}; // switch的case是否合并成一行 AllowShortCaseLabelsOnASingleLine
switch(type)
{
case :
a++;
break;
} // 简短的函数能不能放一行 AllowShortFunctionsOnASingleLine
class TestFuncOneLine
{
void test()
{
a ++;
}
}; void not_one_line()
{
a ++;
} // if 语句能不能放一行 AllowShortIfStatementsOnASingleLine
if (a > b)
{
a ++;
if ( == b)
b ++;
}
else
{
b++;
if ( == a)
{
a = ;
b = ;
}
} // lambda表达式能不能放一行 AllowShortLambdasOnASingleLine
void lambda_one_line()
{
auto lambda = [](int a, int b)
{
return a > b;
}; // TODO: 这里人换行
sort(a.begin(), a.end(), ()[] {
return x < y;
});
} // for等循环能不能放一行 AllowShortLoopsOnASingleLine
// 这个测试没生效
while (true)
{
a ++;
}; do
{
a ++;
}while();
do { a ++ } while(); // TODO:这个宏总被展开
#define TEST(a) do { a ++ } while(0) // 函数声明 返回类型之后要不要断行 AlwaysBreakAfterDefinitionReturnType
int test() {} // 不换行
int
test() {} // 换行 // 函数实现 返回类型之后要不要断行 AlwaysBreakAfterReturnType
int
test()
{
a ++;
} // 字符串换行时,等号后面要不要换行 AlwaysBreakBeforeMultilineStrings
aaaa =
"bbbb" // 换行
"cccc"; aaaa = "bbbb" // 不换行
"cccc"; // 模板声明是否换行 AlwaysBreakTemplateDeclarations
template <typename T>
T foo() {
}
template <typename T>
T foo(int aaaaaaaaaaaaaaaaaaaaa,
int bbbbbbbbbbbbbbbbbbbbb) {
} // 调用函数时,参数是否独占一行 BinPackArguments
func(
a,
b,
c
); funcccccccccccccccccccccccccc(aaaaaaaaaaaaaaaaaaaaaaaaaaaa, bbbbbbbbbbbbbbbbbb,
ccccccccccccccccc, cccccccccccccccccccc); // 声明或者实现函数时,参数是否独占一行 BinPackParameters
int
funcccccccccccccccccccccccccc(aaaaaaaaaaaaaaaaaaaaaaaaaaaa, bbbbbbbbbbbbbbbbbb,
ccccccccccccccccc, cccccccccccccccccccc); // 控制大括号的断行方式 BraceWrapping
// BreakBeforeBraces的值为Custom才有效
class foo {}; // 运算符(=、+、、*等)换行方式 BreakBeforeBinaryOperators
LooooooooooongType loooooooooooooooooooooongVariable = someLooooooooooooooooongFunction(); bool value = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa ==
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa &&
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa >
ccccccccccccccccccccccccccccccccccccccccc; // 大括号换行方式 BreakBeforeBraces // 双目运算符的断行方式 BreakBeforeTernaryOperators
int a = a > b ? a : b;
veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongDescription ? firstValue : SecondValueVeryVeryVeryVeryLong; // 初始化列表换行方式 BreakConstructorInitializers
// 继承的换行方式 BreakInheritanceList
class Tttttttttttttttttttttttttttttttttttttttttttttttttttttest : Aaaaaa,Bbbbbbbbb
{
public:
Tttttttttttttttttttttttttttttttttttttttttttttttttttttest() : Aaaaaa(),Bbbbbbbbb() {}
}; // 字符串是否允许换行
std::string str = "loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong str"; // 单行字符数 ColumnLimit // 控制注释中哪些内容不允许换行的正则 CommentPragmas // 是否合并命名空间到一行 CompactNamespaces
namespace Foo { namespace Bar { // 合并
}}
// 不合并
namespace Foo {
namespace Bar {
}
} // 初始化列表是否全放到一行 ConstructorInitializerAllOnOneLineOrOnePerLine
SomeClass::Constructor()
: aaaaaaaa(aaaaaaaa), aaaaaaaa(aaaaaaaa), aaaaaaaa(aaaaaaaaaaaaaaaaaaaaaaaaa) {
return ;
} // 初始化列表换行时,缩进的宽度 ConstructorInitializerIndentWidth
// 发生换行时,缩进的宽度 ContinuationIndentWidth // 大括号数组是否有空格 Cpp11BracedListStyle
vector<int> x{, , , }; // cpp11风格,没有
vector<int> x{ , , , }; // 有 // 引用和指针的对齐方式 DerivePointerAlignment
// 不知道这个是用来干啥的 // 完全不格式化(为啥会有这个选项,不格式化不调用不就行了么) DisableFormat // 自动根据当前文件其他地方的格式来格式化函数参数 ExperimentalAutoDetectBinPacking
// 比如说其他地方的参数是每个参数占一行,那它决定按每个参数占一行来格式化
// 这个是实验性的 // 是否自动添加命名空间结束注释 FixNamespaceComments
namespace a
{
foo();
} // 按理来说这里会加个 namspace a的注释,但测试发现没生效。不过如果这里有注释,就会被修正 // 一些第三方的foreach循环宏定义,比如QT的 ForEachMacros // include的合并方式 IncludeBlocks
// 一般按名字来排,按空行分组(因为有些顺序是特定的),注意下面有个 SortIncludes 选项
#include "b.h" #include <lib/main.h>
#include "a.h"
#include <cstd>
#include <yy> // include 优先级 IncludeCategories
// 当上面的IncludeBlocks设置为Regroup,会把include全部排序,排序规则就按这个来 // include规则 ,和上面的差不多 IncludeIsMainRegex // switch的case缩进 IndentCaseLabels
switch(a)
{
case : break; // 不缩进
case : break; // 缩进
} // togo标签是否缩进,文档里有,程序不认这个选项了 IndentGotoLabels // 多层宏定义镶嵌时,缩进方式 IndentPPDirectives
#if FOO
#if BAR
#include <foo>
#endif
#endif // 缩进宽度 IndentWidth // 当返回类型和函数名断行时,函数名是否缩进 IndentWrappedFunctionNames
// 真有这么长的类型和函数名吗?
LoooooooooooooooooooooooooooooooooooooooongReturnType
LoooooooooooooooooooooooooooooooongFunctionDeclaration(); // 代码块开始时,要不要空一行 KeepEmptyLinesAtTheStartOfBlocks
// 这个没生效,可能是需要大括号在行尾的Java风格才有效
if (true) { test(); // 上面空一行
} // 指定格式化提哪个语言 Language // 匹配一对开始和结束的宏 MacroBlockBegin MacroBlockEnd
NS_MAP_BEGIN
foo();
NS_MAP_END // 允许连续空多少行 MaxEmptyLinesToKeep
if (true)
{
a ++; b ++;
} // 命名空间里的代码是否缩进 NamespaceIndentation
namespace out {
int i; // 不缩进
namespace in {
int i; // 缩进
}
} // 表示命名空间的宏(我用不着,暂时不测试) NamespaceMacros // 这几个Penalty暂时不知道是啥,下面的链接有讨论
// https://stackoverflow.com/questions/26635370/in-clang-format-what-do-the-penalties-do
// 大概意思是当刚好超过行宽,但又不超几个字符时,如果断行
// 我试了下PenaltyBreakBeforeFirstCallParameter = 19, PenaltyExcessCharacter = 10
// 时,下面那个函数调用就不换行。但这个数值是根据算法来的,算法把各种因素给定一些值,得
// 出不同换行时的penalty值,其大小没有标准可参考 // PenaltyBreakAssignment
auto loooooooooooooooooooooooooooooooooooooooooooooooooooooooooosong_var = "abc";
// PenaltyBreakBeforeFirstCallParameter
Namespaces::Are::Pervasive::SomeReallyVerySuperDuperLooooooooongFunctionName(args);
// PenaltyBreakComment
// PenaltyBreakFirstLessLess
// PenaltyBreakString
// PenaltyBreakTemplateDeclaration
// PenaltyExcessCharacter
// PenaltyReturnTypeOnItsOwnLine // 指针的*号放哪 PointerAlignment
int* a; // left
int *a; // right // 匹配字符串中代码的正则,如果匹配到,字符串的代码将会被格式化 RawStringFormats // 是否格式化注释(这里测试没生效) ReflowComments
/* second veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of information */ // 是否对include 排序 SortIncludes
// 见上面的IncludeBlocks测试 // using xxx是否需要排序 SortUsingDeclarations
using std::cout;
using std::cin; // 哪些操作后面需要加空格
// SpaceAfterCStyleCast: (int) i
// SpaceAfterLogicalNot: ! someExpression()
// SpaceAfterTemplateKeyword: template <int> void foo();
// SpaceBeforeAssignmentOperators: int a = 5
// SpaceBeforeCpp11BracedList: vector<int> { 1, 2, 3 }
// SpaceBeforeCtorInitializerColon: Foo::Foo() : a(a) {}
// SpaceBeforeInheritanceColon: class Foo : Bar {}
// SpaceBeforeParens: if (true) {}
// SpaceBeforeRangeBasedForLoopColon: for (auto v : values) {}
// SpaceInEmptyParentheses: f( ) // 括号中间有一个空格
// SpacesBeforeTrailingComments: // aaa //后面有一个空格再接注释
// SpacesInAngles: static_cast< int >(arg) <>中间是否有空格
// SpacesInContainerLiterals: f({a : 1, b : 2, c : 3}); 这个C++没用到
// SpacesInCStyleCastParentheses: x = ( int32 )y 类型转换时,括号要不要加空格
// SpacesInParentheses: t f( Deleted & ) & = delete; 括号要不要加空格,
// SpacesInSquareBrackets: int a[ 5 ]; 数组的中括号要不要加空格 // 使用哪个标准 Standard // tab宽度 TabWidth // 是否用tab缩进 UseTab // TODO: 不能强制if换行时加大括号
if (true)
a+ = bbbbbbbbbbbbbbbbbbbbb + ccccccccccccccccccccccc + ddddddddddddddddddddddd;
我自己用的配置
# http://clang.llvm.org/docs/ClangFormatStyleOptions.html
# dump by clang-format --dump-config ---
Language: Cpp
# BasedOnStyle: LLVM
AccessModifierOffset: -4
AlignAfterOpenBracket: Align
AlignConsecutiveMacros: true
AlignConsecutiveAssignments: true
AlignConsecutiveDeclarations: false
AlignEscapedNewlines: Left
AlignOperands: true
AlignTrailingComments: true
AllowAllArgumentsOnNextLine: true
AllowAllConstructorInitializersOnNextLine: true
AllowAllParametersOfDeclarationOnNextLine: false
AllowShortBlocksOnASingleLine: false
AllowShortCaseLabelsOnASingleLine: true
AllowShortFunctionsOnASingleLine: Inline
AllowShortLambdasOnASingleLine: Inline
AllowShortIfStatementsOnASingleLine: WithoutElse
AllowShortLoopsOnASingleLine: true
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: MultiLine
BinPackArguments: true
BinPackParameters: true
BreakBeforeBraces: Allman
BraceWrapping:
AfterCaseLabel: true
AfterClass: true
AfterControlStatement: true
AfterEnum: true
AfterFunction: true
AfterNamespace: true
AfterObjCDeclaration: false
AfterStruct: true
AfterUnion: true
AfterExternBlock: true
BeforeCatch: true
BeforeElse: true
IndentBraces: true
SplitEmptyFunction: true
SplitEmptyRecord: true
SplitEmptyNamespace: true
BreakBeforeBinaryOperators: NonAssignment
BreakBeforeInheritanceComma: false
BreakInheritanceList: BeforeColon
BreakBeforeTernaryOperators: true
BreakConstructorInitializersBeforeComma: false
BreakConstructorInitializers: BeforeColon
BreakAfterJavaFieldAnnotations: false
BreakStringLiterals: true
ColumnLimit: 80
CommentPragmas: '^ IWYU pragma:'
CompactNamespaces: false
ConstructorInitializerAllOnOneLineOrOnePerLine: false
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
Cpp11BracedListStyle: 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
- Regex: '^(<|"(gtest|gmock|isl|json)/)'
Priority: 3
- Regex: '.*'
Priority: 1
IncludeIsMainRegex: '(Test)?$'
IndentCaseLabels: false
IndentPPDirectives: BeforeHash
IndentWidth: 4
IndentWrappedFunctionNames: false
JavaScriptQuotes: Leave
JavaScriptWrapImports: true
KeepEmptyLinesAtTheStartOfBlocks: true
MacroBlockBegin: ''
MacroBlockEnd: ''
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
ObjCBinPackProtocolList: Auto
ObjCBlockIndentWidth: 2
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: true
PenaltyBreakAssignment: 2
PenaltyBreakBeforeFirstCallParameter: 19
PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120
PenaltyBreakString: 1000
PenaltyBreakTemplateDeclaration: 10
PenaltyExcessCharacter: 10
PenaltyReturnTypeOnItsOwnLine: 60
PointerAlignment: Right
ReflowComments: true
SortIncludes: false
SortUsingDeclarations: false
SpaceAfterCStyleCast: false
SpaceAfterLogicalNot: false
SpaceAfterTemplateKeyword: true
SpaceBeforeAssignmentOperators: true
SpaceBeforeCpp11BracedList: false
SpaceBeforeCtorInitializerColon: true
SpaceBeforeInheritanceColon: true
SpaceBeforeParens: ControlStatements
SpaceBeforeRangeBasedForLoopColon: true
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 1
SpacesInAngles: false
SpacesInContainerLiterals: false
SpacesInCStyleCastParentheses: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
Standard: Cpp11
StatementMacros:
- Q_UNUSED
- QT_REQUIRE_VERSION
TabWidth: 4
UseTab: Never
...
格式化后的效果
/* 测试clang-format格式化效果
*/ class Test
{
// 对齐这个public修饰符 AccessModifierOffset: -2
public:
}; // 括号断行后参数对齐方式 AlignAfterOpenBracket
void ttttttt(int aaaaaaa, int bbbbbbbbb, int ccccccccc, int ddddddddd,
int eeeeeeeeeeeeeee, int ffffffffffffffffffffffffffffffff)
{
}
// TODO: 不能实现下面的对齐方式
// 1. 下一行长度大于上一行
// 2. 换行缩进为4格
//
void ttttttt(int aaaaaaa, int bbbbbbbbb, int ccccccccc, int ddddddddd,
int eeeeeeeeeeeeeee, int ffffffffffffffffffffffffffffffff)
{
} // 赋值时等号对齐 AlignConsecutiveAssignments
int aaaaaaa = ;
int b = ;
int ccccc = ; // 变量名左对齐,应该和上面的冲突 AlignConsecutiveDeclarations
int aaaa = ;
float b = ;
std::string ccc = ; // 宏对齐 AlignConsecutiveMacros
#define SHORT_NAME 42
#define LONGER_NAME 0x007f
#define EVEN_LONGER_NAME (2)
#define foo(x) (x * x)
#define bar(y, z) (y + z) // 断行符的对齐 AlignEscapedNewlines
#define A \
int aaaa; \
int b; \
int dddddddddd // 运算变量对齐 AlignOperands
int sum = aaaaaaaaaaa + bbbbbbbbbb + ccccccccccccccccccc + ddddddddddddddd
+ eeeeeeeeeee + fff; // 是否对齐行尾注释 AlignTrailingComments
int x; // test xxxxxxxx
int yyyyyyyyyyyyy; // test yyyyyyyyy
int zzzz; // test zzzzzzz // 调用函数时,参数的断行方式 AllowAllArgumentsOnNextLine
looooooooooooooooooooooooooooooooooooooooooooooong_call(aaaaaaaaaa, bbbbbbbb,
cccccccc); // 构造函数初始化列表断行方式 AllowAllConstructorInitializersOnNextLine
class LongInitializers
{
public:
LongInitializers()
: aaaaaaaaaaaaaaaaa(), bbbbbbbbbbbbbbbbbb(), ccccccccccccc()
{
}
}; // 函数声明时参数的断行方式 AllowAllParametersOfDeclarationOnNextLine
// 上面的AlignAfterOpenBracket优先级更高,会影响这个
int ddddddddddddddddddddddddddddddddddddddddd(int aaaaaa, int bbbbbbb,
int cccccccccccc); // 是否把简短的代码合并成一行 AllowShortBlocksOnASingleLine
// 这个没生效,而且和文档也对不上了。文档有好几个值,配置只接受 true flase
if (a > b) a++;
while (true)
{
a++;
b++;
}; // switch的case是否合并成一行 AllowShortCaseLabelsOnASingleLine
switch (type)
{
case : a++; break;
} // 简短的函数能不能放一行 AllowShortFunctionsOnASingleLine
class TestFuncOneLine
{
void test() { a++; }
}; void not_one_line()
{
a++;
} // if 语句能不能放一行 AllowShortIfStatementsOnASingleLine
if (a > b)
{
a++;
if ( == b) b++;
}
else
{
b++;
if ( == a)
{
a = ;
b = ;
}
} // lambda表达式能不能放一行 AllowShortLambdasOnASingleLine
void lambda_one_line()
{
auto lambda = [](int a, int b) {
return a > b;
}; // TODO: 这里人换行
sort(
a.begin(), a.end(), ()[] { return x < y; });
} // for等循环能不能放一行 AllowShortLoopsOnASingleLine
// 这个测试没生效
while (true)
{
a++;
}; do
{
a++;
} while ();
do
{
a++
} while (); // TODO:这个宏总被展开
#define TEST(a) \
do \
{ \
a++ \
} while () // 函数声明 返回类型之后要不要断行 AlwaysBreakAfterDefinitionReturnType
int test() {} // 不换行
int test() {} // 换行 // 函数实现 返回类型之后要不要断行 AlwaysBreakAfterReturnType
int test()
{
a++;
} // 字符串换行时,等号后面要不要换行 AlwaysBreakBeforeMultilineStrings
aaaa = "bbbb" // 换行
"cccc"; aaaa = "bbbb" // 不换行
"cccc"; // 模板声明是否换行 AlwaysBreakTemplateDeclarations
template <typename T> T foo() {}
template <typename T>
T foo(int aaaaaaaaaaaaaaaaaaaaa, int bbbbbbbbbbbbbbbbbbbbb)
{
} // 调用函数时,参数是否独占一行 BinPackArguments
func(a, b, c); funcccccccccccccccccccccccccc(aaaaaaaaaaaaaaaaaaaaaaaaaaaa, bbbbbbbbbbbbbbbbbb,
ccccccccccccccccc, cccccccccccccccccccc); // 声明或者实现函数时,参数是否独占一行 BinPackParameters
int funcccccccccccccccccccccccccc(aaaaaaaaaaaaaaaaaaaaaaaaaaaa,
bbbbbbbbbbbbbbbbbb, ccccccccccccccccc,
cccccccccccccccccccc); // 控制大括号的断行方式 BraceWrapping
// BreakBeforeBraces的值为Custom才有效
class foo
{
}; // 运算符(=、+、、*等)换行方式 BreakBeforeBinaryOperators
LooooooooooongType loooooooooooooooooooooongVariable =
someLooooooooooooooooongFunction(); bool value = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
== aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
&& aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
> ccccccccccccccccccccccccccccccccccccccccc; // 大括号换行方式 BreakBeforeBraces // 双目运算符的断行方式 BreakBeforeTernaryOperators
int a = a > b ? a : b;
veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongDescription
? firstValue
: SecondValueVeryVeryVeryVeryLong; // 初始化列表换行方式 BreakConstructorInitializers
// 继承的换行方式 BreakInheritanceList
class Tttttttttttttttttttttttttttttttttttttttttttttttttttttest : Aaaaaa, Bbbbbbbbb
{
public:
Tttttttttttttttttttttttttttttttttttttttttttttttttttttest()
: Aaaaaa(), Bbbbbbbbb()
{
}
}; // 字符串是否允许换行
std::string str = "looooooooooooooooooooooooooooooooooooooooooooooooooooooooooo"
"ooooooooooooong str"; // 单行字符数 ColumnLimit // 控制注释中哪些内容不允许换行的正则 CommentPragmas // 是否合并命名空间到一行 CompactNamespaces
namespace Foo
{
namespace Bar
{ // 合并
}
} // namespace Foo
// 不合并
namespace Foo
{
namespace Bar
{
}
} // namespace Foo // 初始化列表是否全放到一行 ConstructorInitializerAllOnOneLineOrOnePerLine
SomeClass::Constructor()
: aaaaaaaa(aaaaaaaa), aaaaaaaa(aaaaaaaa), aaaaaaaa(aaaaaaaaaaaaaaaaaaaaaaaaa)
{
return ;
} // 初始化列表换行时,缩进的宽度 ConstructorInitializerIndentWidth
// 发生换行时,缩进的宽度 ContinuationIndentWidth // 大括号数组是否有空格 Cpp11BracedListStyle
vector<int> x{, , , }; // cpp11风格,没有
vector<int> x{, , , }; // 有 // 引用和指针的对齐方式 DerivePointerAlignment
// 不知道这个是用来干啥的 // 完全不格式化(为啥会有这个选项,不格式化不调用不就行了么) DisableFormat // 自动根据当前文件其他地方的格式来格式化函数参数 ExperimentalAutoDetectBinPacking
// 比如说其他地方的参数是每个参数占一行,那它决定按每个参数占一行来格式化
// 这个是实验性的 // 是否自动添加命名空间结束注释 FixNamespaceComments
namespace a
{
foo();
} // namespace a // 一些第三方的foreach循环宏定义,比如QT的 ForEachMacros // include的合并方式 IncludeBlocks
// 一般按名字来排,按空行分组(因为有些顺序是特定的),注意下面有个 SortIncludes 选项
#include "b.h" #include <lib/main.h>
#include "a.h"
#include <cstd>
#include <yy> // include 优先级 IncludeCategories
// 当上面的IncludeBlocks设置为Regroup,会把include全部排序,排序规则就按这个来 // include规则 ,和上面的差不多 IncludeIsMainRegex // switch的case缩进 IndentCaseLabels
switch (a)
{
case : break; // 不缩进
case : break; // 缩进
} // togo标签是否缩进,文档里有,程序不认这个选项了 IndentGotoLabels // 多层宏定义镶嵌时,缩进方式 IndentPPDirectives
#if FOO
#if BAR
#include <foo>
#endif
#endif // 缩进宽度 IndentWidth // 当返回类型和函数名断行时,函数名是否缩进 IndentWrappedFunctionNames
// 真有这么长的类型和函数名吗?
LoooooooooooooooooooooooooooooooooooooooongReturnType
LoooooooooooooooooooooooooooooooongFunctionDeclaration(); // 代码块开始时,要不要空一行 KeepEmptyLinesAtTheStartOfBlocks
// 这个没生效,可能是需要大括号在行尾的Java风格才有效
if (true)
{ test(); // 上面空一行
} // 指定格式化提哪个语言 Language // 匹配一对开始和结束的宏 MacroBlockBegin MacroBlockEnd
NS_MAP_BEGIN
foo();
NS_MAP_END // 允许连续空多少行 MaxEmptyLinesToKeep
if (true)
{
a++; b++;
} // 命名空间里的代码是否缩进 NamespaceIndentation
namespace out
{
int i; // 不缩进
namespace in
{
int i; // 缩进
}
} // namespace out // 表示命名空间的宏(我用不着,暂时不测试) NamespaceMacros // 这几个Penalty暂时不知道是啥,下面的链接有讨论
// https://stackoverflow.com/questions/26635370/in-clang-format-what-do-the-penalties-do
// 大概意思是当刚好超过行宽,但又不超几个字符时,如果断行
// 我试了下PenaltyBreakBeforeFirstCallParameter = 19, PenaltyExcessCharacter = 10
// 时,下面那个函数调用就不换行。但这个数值是根据算法来的,算法把各种因素给定一些值,得
// 出不同换行时的penalty值,其大小没有标准可参考 // PenaltyBreakAssignment
auto loooooooooooooooooooooooooooooooooooooooooooooooooooooooooosong_var =
"abc";
// PenaltyBreakBeforeFirstCallParameter
Namespaces::Are::Pervasive::SomeReallyVerySuperDuperLooooooooongFunctionName(args);
// PenaltyBreakComment
// PenaltyBreakFirstLessLess
// PenaltyBreakString
// PenaltyBreakTemplateDeclaration
// PenaltyExcessCharacter
// PenaltyReturnTypeOnItsOwnLine // 指针的*号放哪 PointerAlignment
int *a; // left
int *a; // right // 匹配字符串中代码的正则,如果匹配到,字符串的代码将会被格式化 RawStringFormats // 是否格式化注释(这里测试没生效) ReflowComments
/* second veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of information */ // 是否对include 排序 SortIncludes
// 见上面的IncludeBlocks测试 // using xxx是否需要排序 SortUsingDeclarations
using std::cout;
using std::cin; // 哪些操作后面需要加空格
// SpaceAfterCStyleCast: (int) i
// SpaceAfterLogicalNot: ! someExpression()
// SpaceAfterTemplateKeyword: template <int> void foo();
// SpaceBeforeAssignmentOperators: int a = 5
// SpaceBeforeCpp11BracedList: vector<int> { 1, 2, 3 }
// SpaceBeforeCtorInitializerColon: Foo::Foo() : a(a) {}
// SpaceBeforeInheritanceColon: class Foo : Bar {}
// SpaceBeforeParens: if (true) {}
// SpaceBeforeRangeBasedForLoopColon: for (auto v : values) {}
// SpaceInEmptyParentheses: f( ) // 括号中间有一个空格
// SpacesBeforeTrailingComments: // aaa //后面有一个空格再接注释
// SpacesInAngles: static_cast< int >(arg) <>中间是否有空格
// SpacesInContainerLiterals: f({a : 1, b : 2, c : 3}); 这个C++没用到
// SpacesInCStyleCastParentheses: x = ( int32 )y 类型转换时,括号要不要加空格
// SpacesInParentheses: t f( Deleted & ) & = delete; 括号要不要加空格,
// SpacesInSquareBrackets: int a[ 5 ]; 数组的中括号要不要加空格 // 使用哪个标准 Standard // tab宽度 TabWidth // 是否用tab缩进 UseTab // TODO: 不能强制if换行时加大括号
if (true)
a + = bbbbbbbbbbbbbbbbbbbbb + ccccccccccccccccccccccc
+ ddddddddddddddddddddddd;
总体来说,clang-format表现出色。但是有一些小地方不太满意
// 为什么不是下一行比上一行长
void test(int aaaaaaaaaaaaaa, int bbbbbbbbbbb,
int ccccccccccccccccc); // if换行不能强制换加大括号
if (true)
a ++; // 这里为什么要换行
sort(
a.begin(), a.end(), ()[] { return x < y; });
另外,clang-format不能指定配置文件的路径,而我不喜欢把这些文件和源代码文件放在一起,为此还写了个批量格式化的脚本。上面的例子只是写来测试,要看clang-format的格式化效果,直接在github上看对应项目的代码即可,比如Linux kernel。
uncrustify这工具现在在github维护,也是比较活跃,但我没见过用这个工具格式化的项目,而且上面也给出了格式化的效果,这里就不再测试了。
astyle在sourceforge上,更新并不频繁,格式化选项比较少,比如说没有提提供宏定义对齐等。
不过有趣的是,uncrustify和astyle都提供了强制给if加大括号的选项,唯独clang-format没有。
使用工具后,好处是代码风格统一了,不用管其他人写代码的风格怎么样。只要风格和工具格式化出来的不一样,就不允许提交(比如CI自动运行clang-format,如果提交的代码与clang-format格式化出来的不一致,则拒绝合并代码)。坏处是手写基本写不出来这样的代码了,基本都需要工具格式化后才能提交,好在现在很多编辑器都提供format on save选项,开启即可。
不过,这只是格式化的问题,其实代码风格中更大的问题是大小写问题,比如大驼峰的写法和linux下划线的写法,这个目前还没有发现对应的工具。Google出过一个工具,但是效果并不是太好,https://github.com/google/styleguide/tree/gh-pages/cpplint。
测试clang-format的格式化效果的更多相关文章
- Java中利用MessageFormat对象实现类似C# string.Format方法格式化
我们在写C#代码的时候常常会使用到string.Format("待格式化字符串{0},{1},....",参数1,参数2,...),来格式化字符串,特别是拼接字符的时候,这种方式使 ...
- clang format 官方文档自定义参数介绍(中英文)
官方文档:http://clang.llvm.org/docs/ClangFormatStyleOptions.html 中文 在代码中配置样式 当使用 clang::format::reformat ...
- 在Xcode中使用Clang Format
Xcode中的Re-Indent,顾名思义,只是一个调整缩进的功能,完全依赖它来进行代码格式化显然不够用.我们使用了一个叫做ClangFormat-Xcode的插件,配合Re-Indent一起来做代码 ...
- string.Format字符串格式化说明(转)
string.Format字符串格式化说明 www.111cn.net 编辑:Crese 来源:转载 先举几个简单的应用案例: 1.格式化货币(跟系统的环境有关,中文系统默认格式化人民币,英文系统 ...
- 第3.11节 Python强大的字符串格式化新功能:format字符串格式化的格式控制
第3.11节 format字符串格式化的格式控制 一. 引言 上节介绍了四种format进行字符串格式化的 ...
- Clang Format
1,最近项目代码要求规范化,在网上找了个Xcode插件:Clang Format ,下载地址:https://github.com/travisjeffery/ClangFormat-Xcode 2, ...
- Python中用format函数格式化字符串的用法
这篇文章主要介绍了Python中用format函数格式化字符串的用法,格式化字符串是Python学习当中的基础知识,本文主要针对Python2.7.x版本,需要的朋友可以参考下 自python2. ...
- String.Format数字格式化参考
String.Format数字格式化输出 {0:N2} {0:D2} {0:C2} (转) 数字 {0:N2} 12.36 数字 {0:N0} 13 货币 {0:c2} $12.36 货币 {0:c4 ...
- django datetime format 日期格式化
django datetime format 日期格式化 www.jx-lab.com python 中 date,datetime,time对象都支持strftime(format)方法,但有一些区 ...
随机推荐
- Sql题目精选练习
1.每日经典sql 1.1.1 根据三张关系表查询雇员中工资最高的雇员的员工姓名.工资和部门号. salary(工资表) employee(员工表) department(部门表) Sql语句: SE ...
- 阶段5 3.微服务项目【学成在线】_day03 CMS页面管理开发_16-异常处理-可预知异常处理-自定义异常类型和抛出类
在common工程创建捕获异常的类:CustomException Runtime叫做运行异常.在代码中抛出的话 对我们的代码没有可侵入性 如果在代码上抛出 如果改成Exception 这时候就会有错 ...
- ansible安装、配置ssh、hosts、测试连接
.安装ansible 1.1.源码安装 源码安装参照 https://www.cnblogs.com/guxiong/p/7218717.html [root@kube-node3 ~]# .tar. ...
- iOS-ShareSDK的使用(转)
官方下载ShareSDK iOS:http://sharesdk.cn/ ShareSDK社会化分享 包含“社会化分享组件”“社会化登录组件”“第三方评论和赞”三大模块,并有详尽的数据统计后台,助力移 ...
- swift 第二课 基础知识-2
setter 和getter 的使用--> 适合计算使用 struct Point { var x = 0.0, y=0.0 } struct Size { var width = 0.0, h ...
- python列表删除--remove(),del,pop()
remove()参数为列表元素,若在列表中,删除,不在则报错 如: pop()不带参数时默认删除列表的末尾元素并返回该元素,带参数时该参数为列表元素的下标值 不带参数: 以下标为参数: del 后面可 ...
- ADRMS与office的整合(一)
因为微软之前针对客户的RMS加密服务是一种免费的测试服务,虽然用户很多但实质上还是一种“测试服务”. 后来微软把这个服务商业化了,需要继续使用的话需要打下这个补丁 https://support.mi ...
- Git速成学习第三课:创建与合并分支
本来第三课想记录一下远程仓库的创建与克隆0.0但是想了想还是不写了. 这里写一下分支管理中的创建与合并. Git速成学习笔记整理于廖雪峰老师的官网网站:https://www.liaoxuefeng. ...
- 用户ID与权限
目录 用户ID与权限 文件系统查看 权限ID概览 设置位 黏着位 UMASK chmod与chown 代码附录 chmod title: 用户ID与权限 date: 2019/11/25 21:20: ...
- 前端手势控制图片插件书写三(将transform变化应用在图片和canvas画布上)
注意:transform的scale为负数时,图片会垂直翻转 一.在使用transform将计算得到的变化应用到图片上后,需要考虑到我们每次计算的都是touchmove中本次的差量.在第一次移动过后. ...