5. 规则详解(2) 空格(Spaces)
clang-format 中有很多 SpaceXxx,可自行查看官网说明。
1. 单行注释前的空格(SpacesBeforeTrailingComments)
行尾注释符号(//)之前,空格的数目,默认为 2
- 效果一
// SpacesBeforeTrailingComments: 2
// AlignTrailingComments: true
int x = 1; // 为 x 赋值
float yy = 2.0; // 为 yy 赋值
double zzz = 3.0; // 为 zzz 赋值
- 效果二
// SpacesBeforeTrailingComments: 4
// AlignTrailingComments: true
int x = 1; // 为 x 赋值
float yy = 2.0; // 为 yy 赋值
double zzz = 3.0; // 为 zzz 赋值
2. 小括号内的空格(SpacesInParens)
控制是否在 ( 后和 ) 前插入空格,有两个常用值:
Never:不在括号内加空格Custom:使用子选项精细控制
当设置为 Custom 时,SpacesInParensOptions 下的子选项(布尔值)会逐项生效,控制哪些场景下在 ( 后和 ) 前插入空格
- 效果演示(着重看 Other 和 ExceptDoubleParentheses 组合的情况)
#include <cstdint>
#include <iostream>
// 简单函数,用于示例
int foo(int x, int y) { return x + y; }
void h( ) {} // 空括号示例(InEmptyParentheses 生效时会显示为 "h( )")
void g( ) { std::cout << "g\n"; }
int main( ) {
int a = 1;
int b = 0;
// 条件语句内括号空格示例
if ( a == b ) {
g( );
} else {
std::cout << "not equal\n";
}
// C 风格强制转换示例(InCStyleCasts 控制是否在括号内加空格)
long y = 42;
int32_t x = ( int32_t )y;
// 函数调用括号示例
int result = foo(a, b);
// 双重括号示例(ExceptDoubleParentheses 控制)
// 当 Other=true,ExceptDoubleParentheses=false 时,以下代码会变为 "ok = ( (a = b) );"
// 当 Other=true,ExceptDoubleParentheses=true 时,以下代码会变为 "ok = (( a = b ));"
// 当 Other=false,ExceptDoubleParentheses=true 时,以下代码会变为 "ok = ((a = b));"
// 当 Other=false,ExceptDoubleParentheses=false 时,以下代码会变为 "ok = ((a = b));"
// 注意:只有当左右括号成对包裹同一表达式(如 ((a=b)) 或 if ((a=b)))时,ExceptDoubleParentheses 才会生效
bool ok = ((a = b));
// 循环条件括号示例
for ( int i = 0; i < 3; ++i ) {
if ( i % 2 == 0 ) {
std::cout << i << '\n';
}
}
// 调用带“空括号内空格”的函数
h( );
return 0;
}
3. 小括号前的空格(SpaceBeforeParens)
用来控制是否在某些情况下在 ( 前插入空格,比如 if (, f (),有以下常用枚举值:
Never: # 尽量不加空格。
ControlStatements: # 仅在控制语句关键字后(if/for/while/switch)加空格。
ControlStatementsExceptControlMacros: # 同上,但对某些宏(如 FOR_EACH)不应用。
NonEmptyParentheses: # 仅当括号内部非空时才加空格(f( ) 不加,f( x ) 加)。
Always: # 尽量在所有可放置空格的位置加空格(受语法限制)。
Custom: # 使用 SpaceBeforeParensOptions 逐项精细控制(推荐)。
SpaceBeforeParensOptions 是 Custom 模式下的子选项,可以设置这些布尔子选项来精确控制,如下:
# 控制语句关键字后(if/for/while/switch)是否有空格。
# 例:if (cond) vs if(cond)
AfterControlStatements: true|false
# 函数声明名与 ( 之间是否有空格
# 例:void f (); vs void f();
AfterFunctionDeclarationName: true|false
# 函数定义名与 ( 之间是否有空格。
# 例:void f () {} vs void f() {}
AfterFunctionDefinitionName: true|false
# not 关键字后是否有空格。
# 例:return not (a || b); vs return not(a || b);
AfterNot: true|false
# 重载运算符后是否有空格。
# 例:void operator++ (int); vs void operator++(int);
AfterOverloadedOperator: true|false
注意:各选项互相叠加、且受语法规则限制(例如宏名是否识别为控制宏)
- 效果演示
// 以上5个子选项都设置为 true
#include <concepts>
#include <iostream>
#include <vector>
// 示例函数与声明 / 定义 的差异
void declaration_example ( ); // If `AfterFunctionDeclarationName: true` -> `void declaration_example ();`
void declaration_example ( ) { std::cout << "def\n"; } // If `AfterFunctionDefinitionName: true` -> `void declaration_example () {`
// 重载运算符示例
struct S {
// If `AfterOverloadedOperator: true` -> `void operator++ (int) { ... }`
void operator++ (int) { std::cout << "post++\n"; }
};
int main ( ) {
// 控制语句:if/for/while 的空格由 AfterControlStatements 控制
int a = 1;
int b = 2;
if ( a == b ) { // space: "if( a == b )" vs "if ( a == b )"
std::cout << "equal\n";
} else {
std::cout << "not equal\n";
}
std::vector<int> v = {1, 2, 3};
for ( auto item : v ) { // space: "for( auto item : v )" vs "for ( auto item : v )"
std::cout << item << "\n";
}
// not 操作符示例(AfterNot 控制)
bool flag = not (a > b); // `not (a>b)` vs `not(a>b)`
// 调用函数时,SpaceBeforeParens 通常不影响函数调用本身(多为函数声明/定义与控制语句)
declaration_example( );
return 0;
}
4. 中括号内/前的空格
# 是否在 [ 与 ] 内部插入空格,例如 a[ 5 ] vs a[5]
# 适用场景:数组声明、索引表达式等(lambda 的 [] 不受影响)
SpacesInSquareBrackets: true|false
# 是否在标识符和第一个 [ 之间插入空格,例如 int a [5]; vs int a[5];)
# 对于多维数组只对 “第一个 [” 生效(比如 int multi [2][3]; 后续 [ 不再额外加空格)
SpaceBeforeSquareBrackets: true|false
- 效果一
// SpacesInSquareBrackets: false
// SpaceBeforeSquareBrackets: false
#include <iostream>
#include <vector>
int main ( ) {
// 1) Simple C-style arrays (declaration and indexing)
int a[5] = {0, 1, 2, 3, 4}; // declaration: `int a[5];`
int b[2][3] = {{1, 2, 3}, {4, 5, 6}}; // multi-dimensional array
std::cout << "a[0] = " << a[0] << "\n";
std::cout << "b[1][2] = " << b[1][2] << "\n";
// 2) std::vector indexing
std::vector<int> v = {10, 11, 12};
std::cout << "v[1] = " << v[1] << "\n";
return 0;
}
- 效果二
// SpacesInSquareBrackets: true
// SpaceBeforeSquareBrackets: true
#include <iostream>
#include <vector>
int main ( ) {
// 1) Simple C-style arrays (declaration and indexing)
int a [ 5 ] = {0, 1, 2, 3, 4}; // declaration: `int a[5];`
int b [ 2 ][ 3 ] = {{1, 2, 3}, {4, 5, 6}}; // multi-dimensional array
std::cout << "a[0] = " << a [ 0 ] << "\n";
std::cout << "b[1][2] = " << b [ 1 ][ 2 ] << "\n";
// 2) std::vector indexing
std::vector<int> v = {10, 11, 12};
std::cout << "v[1] = " << v [ 1 ] << "\n";
return 0;
}
5. 尖括号内的空格(SpacesInAngles)
它决定在 < 和 > 符号内部是否添加空格,有以下常用枚举值:
Never:默认值,在尖括号内不添加空格
Always:在尖括号内总是添加空格
Leave:保留原有的空格格式(不修改)
通常使用默认值 Never
- 效果一
// SpacesInAngles: false
#include <iostream>
#include <map>
#include <string>
#include <vector>
// 模板函数示例
template <typename T>
T add (T a, T b) {
return a + b;
}
int main ( ) {
// 1. 简单模板实例化
std::vector<int> numbers = {1, 2, 3, 4, 5};
std::map<std::string, int> wordCount = {{"hello", 3}, {"world", 5}};
// 2. 模板函数调用
int sum = add(10, 20);
std::cout << "Sum: " << sum << std::endl;
double doubleSum = add(3.14, 2.71);
std::cout << "Double sum: " << doubleSum << std::endl;
return 0;
}
- 效果二
// SpacesInAngles: true
#include <iostream>
#include <map>
#include <string>
#include <vector>
// 模板函数示例
template < typename T >
T add (T a, T b) {
return a + b;
}
int main ( ) {
// 1. 简单模板实例化
std::vector< int > numbers = {1, 2, 3, 4, 5};
std::map< std::string, int > wordCount = {{"hello", 3}, {"world", 5}};
// 2. 模板函数调用
int sum = add(10, 20);
std::cout << "Sum: " << sum << std::endl;
double doubleSum = add(3.14, 2.71);
std::cout << "Double sum: " << doubleSum << std::endl;
return 0;
}
6. 其他空格选项(9个)
# 在逻辑非运算符 ! 后是否插入空格。
# true: if ( ! flag )
# false: if ( !flag )
SpaceAfterLogicalNot: true|false
# 在 operator 关键字与紧随的符号之间是否有空格(影响运算符重载声明/定义的外观)。
# true: bool operator == (int) const; vs
# false: bool operator== (int) const;
SpaceAfterOperatorKeyword: true|false
# 在 C 风格强制转换后的类型括号后是否插空格。
# true: x = ( int ) y;
# false: x = ( int )y;
SpaceAfterCStyleCast: true|false
# 在 case 标签的 : 前是否插入空格。
# true: case 1 :
# false: case 1:
SpaceBeforeCaseColon: true|false
# 控制空花括号 {} 内是否留空格(作用于函数体、类、lambda、初始化等)。
# Always: void f() { }
# Block: 仅空块保留空格
# Never: void f() {}
# 注意:这个在 clang-format 22 版本中引入的,我们现在用的版本是 21.1.8。这里不演示了
SpaceInEmptyBraces: SpaceInEmptyBracesStyle
# 设定 // 行尾注释与代码之间的最少空格数(例如 2 则 expr; // comment)。
SpacesBeforeTrailingComments: Unsigned
# 是否在赋值符号 = 左侧强制有空格。
# true: a = 1;
# false: a= 1;
SpaceBeforeAssignmentOperators: true|false
# 范围 for 的冒号 : 前是否有空格。
# true: for (auto v : vec)
# false: for(auto v: vec)
SpaceBeforeRangeBasedForLoopColon: true|false
# 在继承列表的冒号 : 前是否加空格。
# true: class D : B {}
# false: class D: B {}
SpaceBeforeInheritanceColon: true|false
- 效果演示
#include <iostream>
#include <map>
#include <string>
#include <vector>
// SpaceBeforeInheritanceColon
struct Base {};
struct Derived: Base {};
// SpaceInEmptyBraces (Always / Never)
// Always: "void f() { }" Never: "void f() {}"
void emptyBraces () {}
// SpaceAfterOperatorKeyword
struct Op {
bool operator == (int) const { return true; }
};
// SpaceAfterCStyleCast
double d = 3.14;
int fromCStyleCast = ( int )d;
// SpaceAfterLogicalNot
void test_logical_not (bool flag) {
if ( !flag ) {
std::cout << "flag is false\n";
} else {
std::cout << "flag is true\n";
}
}
// SpacesBeforeTrailingComments demonstration
int x1 = 1; // comment
// SpaceBeforeAssignmentOperators
int x2 = 10;
// SpaceBeforeRangeBasedForLoopColon
void test_range_for () {
// 定义一个vector
std::vector<int> vec = {4, 5, 6};
for ( auto v : vec ) {
std::cout << v << ' ';
}
std::cout << '\n';
}
// SpaceBeforeCaseColon
int switch_demo (int n) {
switch ( n ) {
case 1:
return 10;
case 2:
return 20;
default:
return 0;
}
}
int main () {
std::cout << "Derived types exist: " << sizeof(Derived) << "\n";
test_logical_not(false);
test_range_for();
std::cout << "switch_demo(1) = " << switch_demo(1) << "\n";
return 0;
}
本文是博主原创文章,转载请注明来源 明王讲QT







