Clang-format格式化及配置参数

本文章已经生成可运行项目,

Clang-format格式化C代码

Author:Once Day Date:2022年11月3日

漫漫长路有人对你微笑过嘛…

前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。人工智能学习网站 - 点击跳转

参考文档:

文章目录

1.引言

Clang-format是一种代码格式化工具,可以用来格式化各种代码,可以支持以下语言:

C/C++/Java/JavaScript/Objective-C/Protobuf/C#

此外,也可以使用prettier,但是其对c语言支持有限。

使用方法如下:

USAGE: clang-format [options] [<file> ...]

更多的信息可以查找使用帮助。正常来说,使用以下命令就够了:

clang-format -style=可选格式名 [-i] main.c

上面即可根据指定的格式对指定的文件进行格式化,默认的格式有以下种类:

此外还可以指定为InheritParentConfig,表示继承上一级父文件夹内的.clang-format配置,甚至可以指定继承其中的一部分:--style={BaseOnStyle:InheritParentConfig, ColumnLimit:20}

此外可以指定风格为-style=file,表示使用自定义的配置文件

Clang-format的配置文件可以取名为.clang-format或者_clang-format。该文件可以放在根目录或者最近的父目录,Clang-format都会自己去尝试寻找配置文件。

也可以直接指定配置文件的完整路径-style=file:<format_file_path>

下面命令导出配置文件,以此为基础进行自定义(.clang-foramt)

clang-format -style=可选格式名 -dump-config > .clang-format

.clang-format配置文件使用YAML格式,如下:

key1: value1
key2:  value2
#A comment
...

可以在配置文件时,一次性使用多个语言配置:

---
# We'll use defaults from the LLVM style, but with 4 columns indentation.
BasedOnStyle: LLVM
IndentWidth: 4
---
Language: Cpp
# Force pointers to the type for C++.
DerivePointerAlignment: false
PointerAlignment: Left
---
Language: JavaScript
# Use 100 columns for JS.
ColumnLimit: 100
---
Language: Proto
# Don't format .proto files.
DisableFormat: true
---
Language: CSharp
# Use 100 columns for C#.
ColumnLimit: 100
...

也可以在源码里面进行特殊注释,来表明哪一段代码不需要格式化

int formatted_code;
// clang-format off
    void    unformatted_code  ;
// clang-format on
void formatted_code_again;

// clang-format off// clang-format on自身会被格式化。

1.2 下载Clang-tools

Clang-tool是LLVM环境自带的工具集,其除了Clang-format格式化工具外,还有代码检查工具,如Clang-tidy,Clang-check等。

Clang-tool可以被集成在Vim、Emacs、VS code、Git等中,详情参考官方文档:

Clang-format也可以源码的形式集成在应用中

下载有多种方式,最新版本需要在LLVM下载界面进行下载,其被包含在LLVM环境中:

比如Windows下载:

在这里插入图片描述

由于这些下载在github上,因此下载速度有限,可通过浏览器插件安装github下载加速插件,或者使用代理进行下载

安装之后,clang-format即在安装根目录之下:

在这里插入图片描述

将该目录加进PATH环境变量中即可(安装时有这个选项,也可以手动添加)。

此外,诸如VScode,其C/C++扩展插件自带一个捆绑的clang-format和clang-tidy,但是版本可能并不是最新的。

在Linux下,也可以之间通过包管理器来安装:

sudo apt install clang-format

注意,该版本同样大概率不是最新的,因此一些特性是无法使用的

2. 配置字段解释
2.1 language 编程语言
# 语言: None, Cpp, Java, JavaScript, ObjC, Proto, TableGen, TextProto
Language:	Cpp

可以指定当前配置文件为了哪些文件配置的。

2.2 BaseOnStyle 基础风格
BasedOnStyle: LLVM|Google|Chromium|Mozilla|WebKit|Microsoft|GNU

指定基本的风格样式,实际开发时无需从头开始指定所有的格式。

2.3 AccessModifierOffset 访问性修饰符偏移
# 访问说明符(public、private等)的偏移(缩进或者对齐)
AccessModifierOffset:	-4

这个是相对于原来已有的缩进而言:

template <typename type> //模板定义
// template <class type>  较老的实现
class stack //定义一个模板类
{
private: //私有是默认属性,可省略
    //类声明中无法给没有分配空间的变量赋值(只是一起声明了一类变量)
    //某些常量或者静态常量变量(含有存储空间)则可以初始化
    int var;
}

原来的缩进是4个空白字符,这个表明在原来缩进4个字符的情况下偏移量,即回退4个字符,那相当于不缩进了。

2.4 AlignAfterOpenBracket 开括号后的对齐
# 开括号(开圆括号、开尖括号、开方括号)后的对齐: Align, DontAlign, AlwaysBreak(总是在开括号后换行)
AlignAfterOpenBracket:	Align
  • Align,在开括号之后对齐变量

    someLongFunction(argument1,
                     argument2);
    
  • DontAlign, 不对齐,换行后使用ContinuationIndentWidth

    someLongFunction(argument1,
        argument2);
    
  • AlwaysBreak,一行放不下时,总是在一个开括号之后换行。

    someLongFunction(
        argument1, argument2);
    
  • BlockIndext,一行放不下时,总是在一个开括号之后换行,且在新行关闭尾括号。仅限于圆括号

    someLongFunction(
        argument1, argument2
    )
    
2.5 AlignArrayOfStructures 对齐结构体数组

当数组的列数相等时,会对齐每行的文本。

  • Left,左对齐列:
struct test demo[] =
{
    {56, 23,    "hello"},
    {-1, 93463, "world"},
    {7,  5,     "!!"   }
};
  • Right,右对齐列:
struct test demo[] =
{
    {56,    23, "hello"},
    {-1, 93463, "world"},
    { 7,     5,    "!!"}
};

使用None表示不用对齐

2.6 AlignConsecutiveAssignments 对齐连续赋值
# 连续赋值时,对齐所有等号
AlignConsecutiveAssignments:	true

下面的格式是连续赋值:

int a            = 1;
int somelongname = 2;
double c         = 3;

该选项有两种生效方法,低版本只支持指定固定的模式,如下面其中一种:

#配置一个参数:None - Consecutive - AcrossEmptyLines - AcrossComments - AcrossEmptyLinesAndComments
AlignConsecutiveAssignments: AcrossEmptyLinesAndComments

最新版本支持分别指定属性,包括额外对混合元素符(+=等)的支持:

AlignConsecutiveAssignments:
  Enabled: true
  AcrossEmptyLines: true
  AcrossComments: true
  AlignCompound: true
  PadOperators: true
  • bool Enabled: true默认的连续赋值对齐在以下的情况下生效:
int a            = 1;
int somelongname = 2;
double c         = 3;

int aaaa : 1;
int b    : 12;
int ccc  : 8;

int         aaaa = 12;
float       b = 23;
std::string ccc;
  • bool AcrossEmptyLines可以跨越空白行进行对齐
true:
int a            = 1;
int somelongname = 2;
double c         = 3;

int d            = 3;

false:
int a            = 1;
int somelongname = 2;
double c         = 3;

int d = 3;
  • bool AcrossComments可以跨越注释行进行对齐
true:
int d    = 3;
/* A comment. */
double e = 4;

false:
int d = 3;
/* A comment. */
double e = 4;
  • bool AlignCompound混合运算符+=会对齐于=(仅限于连续赋值)
true:
a   &= 2;
bbb  = 2;

false:
a &= 2;
bbb = 2;
  • bool PadOperators混合运算符填补对齐到所有左值的最右边边界。(仅限于连续赋值)
true:
a   >>= 2;
bbb   = 2;

a     = 2;
bbb >>= 2;

false:
a >>= 2;
bbb = 2;

a     = 2;
bbb >>= 2;
2.7 AlignConsecutiveBitFields 位段对齐

主要用于结构体位段的对齐,如下:

struct aa {
    int test : 4;
    int b    : 5;
    int c    : 8;
};

其支持以下属性:

None - Consecutive - AcrossEmptyLines - AcrossComments - AcrossEmptyLinesAndComments

其设置方法和属性与AlignConsecutiveAssignments一致。

AlignConsecutiveBitFields: AcrossEmptyLinesAndComments
#或者
AlignConsecutiveBitFields:
  Enabled: true
  AcrossEmptyLines: true
  AcrossComments: true
2.8 AlignConsecutiveDeclarations 连续声明对齐

可以对齐变量等连续声明的语句。

int         aaaa = 12;
float       b    = 23;
std::string ccc;
const char  hexdigits[] = "0123456789abcdef";
void        Ipv6_deal(const uint16_t *a);

int main(const uint16_t *a, const uint16_t *k) { ... }

需要注意,这个方法配置最好不要跨过空白行,因为容易把函数定义也给对齐了

其支持以下属性:

None - Consecutive - AcrossEmptyLines - AcrossComments - AcrossEmptyLinesAndComments

其设置方法和属性与AlignConsecutiveAssignments一致。

AlignConsecutiveDeclarations: AcrossComments
#或者
AlignConsecutiveDeclarations:
  Enabled: true
  AcrossEmptyLines: false
  AcrossComments: true
2.9 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)

需要注意,这个方法配置最好不要跨过空白行,因为空白行可以用来做段分割符

其支持以下属性:

None - Consecutive - AcrossEmptyLines - AcrossComments - AcrossEmptyL