c++ - 数学表达式中奇怪的 clang 格式

标签 c++ clang-format

我想知道如何解决我在使用 clang-format 和 C++ 中更长的数学表达式时遇到的一些奇怪问题。假设我们在test.h中保存了如下示例代码:

void TestFunction() {
  int long_int_variable_name = 1;
  int result = (long_int_variable_name + long_int_variable_name) * long_int_variable_name - 1;
}

我们可以通过以下方式使用 Google 样式对其进行格式化:

clang-format -style=google -dump-config > .clang-format
clang-format -i -style=file test.h

这会为 result 生成一个格式相当笨拙的表达式:

void TestFunction() {
  int long_int_variable_name = 1;
  int result = (long_int_variable_name + long_int_variable_name) *
                   long_int_variable_name -
               1;
}

看起来它在乘法的第二个操作数之前添加了一个行继续缩进,但在减法的第二个操作数之前对齐回到行的开头。除此之外,为什么它甚至将 1 放到了新的一行?看起来它正试图根据数学优先级在视觉上更紧密/更松散地耦合操作数,但它太过火了。

所以这里的主要问题是

  • 为什么 clang 决定以一种看似笨拙的方式对其进行格式化?
  • 我怎样才能使这种类型的表达式的格式更清晰,或者我可以使用哪些选项来使它看起来合理?

我认为仅当其余代码无法放入当前行时才换行的内容是一个很好的起点。之后,决定在何处缩进有助于改进它。

最佳答案

Short and dirty answer: there's a trick that works in this case.

{
    int result = -d + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa *
                          cccccccccccccccccccccccccccccccccc;
}

如果您不喜欢这样,请为计算的中间结果命名。


这个答案从何而来?有更好的答案吗?

通过一些实验,我们可以找出 clang 在这里做了什么。让我们比较一下 AlignOperands: truefalse:

// AlignOperands: true
{
    int result = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa *
                     cccccccccccccccccccccccccccccccccc -
                 d;
}

// AlignOperands: false
{
    int result = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa *
            cccccccccccccccccccccccccccccccccc -
        d;
}

// Note: these examples use IndentWidth: 4, ContinuationIndentWidth: 8

在这两种情况下,乘法的第二个操作数比加法的第二个操作数多了一个缩进。所以看起来 clang 试图表达乘法比加法更紧密的事实。这在这里并不是真正的问题。

这里的问题是 d 被放在它自己的行上。为什么?

似乎 clang-format 已经决定,由于加法的第一个操作数跨越多行,因此在第二个操作数之后必须有一个换行符。而且因为乘法的第二个操作数有一个额外的缩进,所以它看起来格外奇怪。

搜索 clang-format option对于“操作数”、“缩进”、“优先级”、“乘法”等,没有透露任何相关选项。这给我们留下了几个潜在的方法。


选项 1:找到一些创造性的技巧来编写代码,这样 clang-format 就不会搞砸了。在这种情况下,切换被加数的顺序是诀窍:

{
    int result = -d + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa *
                          cccccccccccccccccccccccccccccccccc;
}

不幸的是,现在我们正在根据我们的格式化工具做出代码编写决定,这有点倒退并导致混淆(自然的问题出现了:为什么是 -d + x 而不是更简单的 x - d?)。


选项 2:通常还具有增加代码可读性的额外好处的另一个选项是为计算的中间结果创建名称。例如:

{
    double revenue = price_per_unit * num_units_sold;
    double profit = revenue - cost;
}

这真的可以帮助那些原本会问的读者,aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa * cccccccccccccccccccccccccccccccccc 到底是什么意思?


默认选项:最后一个选项是在相关代码块周围添加 clang-format offclang-format on 注释.我不太喜欢这个,因为它给源代码增加了很多困惑(2 行用于开/关,另外还有一行解释你为什么要关闭它),但它总是一个考虑的选项基于上下文。

关于c++ - 数学表达式中奇怪的 clang 格式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57778804/

相关文章:

c++ - 在构造函数中将 break 放在冒号之前和逗号之后

clang-format - 如何在C99中将指定的初始值设定项与 clang-format 对齐?

cmake - 用Clang-Format格式化CMakeLists.txt

c++ - 获取派生模板实例化的运行时类型

c++ - 如何使 C++ 预编译器执行 "loop"

c++ - 在 cmake 中,cmake 文件夹和 CMakeLists.txt 可以放在不同的文件夹中吗?

c++ - 我如何使用 clang-format 缩进 C++ pragma?

c++ - 在 vector 中存储对象

包含功能 header 的 C++ 给出错误 '__dest' 未命名类型

c++ - 标题中的缩进成员