使用 clang 格式缩进预处理器指令

Posted

技术标签:

【中文标题】使用 clang 格式缩进预处理器指令【英文标题】:Indenting preprocessor directives with clang-format 【发布时间】:2014-08-20 00:00:49 【问题描述】:

我正在做一个 c++ 项目,我在其中使用了很多 #pragma omp。我使用美妙的 clang 格式来保持整洁,但它总是删除所有预处理器指令的缩进。有没有办法改变这种行为?还是有其他更值得推荐的格式化工具?还是我应该完全避免使用这些工具?

【问题讨论】:

从历史上看,预处理器指令必须从第一列开始,许多人仍然习惯于在第一列中至少放置前导 # 指令标记行。 我明白...但你明白我的意思,不是吗?由于“#pragma omp”应用于块(缩进),因此看到这些指令也缩进更令人愉快...... 我也有同样的问题。我只能找到一个开放的bug report。我希望他们能尽快实施。 我不知道错误报告。但他们似乎意识到了这个问题:) 随着即将到来的 OpenMP 功能在铿锵声中,我相信这将获得一些动力...... 有两个相关的未解决的错误报告:36019 和 36020 【参考方案1】:

从 6.0 版开始,可以使用选项 IndentPPDirectives。用法在this review 中描述。

使用IndentPPDirectives: None 会导致:

#if FOO
#if BAR
#include <foo>
#endif
#endif

虽然IndentPPDirectives: AfterHash 给出:

#if FOO
#  if BAR
#    include <foo>
#  endif
#endif

编辑:有关clang-format 版本 9 中引入的BeforeHash 选项的详细信息,请参阅@Gabriel Staples 的answer。

【讨论】:

据我所知(通过尝试),这不会缩进# pragma omp... 以匹配周围的代码。相反,它只会根据语句嵌套在其他指令中的级别缩进,例如您显示的#if 现在还有IndentPPDirectives: BeforeHash 选项!在这里查看我的答案:***.com/a/66004745/4561887。 注意:这里是 Clang 格式的版本 6 文档:releases.llvm.org/6.0.0/tools/clang/docs/…。最新的文档(当前版本 12)总是可以在这里找到:clang.llvm.org/docs/ClangFormatStyleOptions.html【参考方案2】:

您可能只想自己修补它并提出拉取请求。

这并不难,我曾经提出过类似的普通拉取请求。 clang 格式的代码非常整洁。 Clang-format 已经以您想要的方式处理代码 cmets,将它们与周围的代码对齐(至少它具有启用此功能的选项),因此制作一个补丁来以相同的方式处理某些 PP 指令应该很简单。

或者,您可以自己编写补丁并使用额外选项从源代码自己编译clang,以便在您的项目中使用。在决定将补丁发送给他们之前,我也这样做了。

我真的只花了几个小时就弄清楚了如何做到这一点,他们的代码比许多其他开源项目的代码干净得多

【讨论】:

我会研究它,如果它真的不那么难,我会去做。但现在我正忙于工作,所以可能在 2 或 3 个月内...... 您在这方面取得了一些进展吗? :-) 高度赞赏的功能!【参考方案3】:

已经很晚了,但这是您正在寻找的解决方案。 它将编译指示与代码块一起格式化。 您可以在他们最终支持 pragma 缩进之前使用它。

https://github.com/MedicineYeh/p-clang-format

主要概念是替换字符串,以便格式化程序在这些 pragma 上使用“正确”规则。动机示例如下。

# Replace "#pragma omp" by "//#pragma omp"
sed -i 's/#pragma omp/\/\/#pragma omp/g' ./main.c
# Do format
clang-format ./main.c
# Replace "// *#pragma omp" by "#pragma omp"
sed -i 's/\/\/ *#pragma omp/#pragma omp/g' ./main.c

【讨论】:

很好的答案,只要您的代码没有任何已被注释掉的#pragmas 被重新启用。如果您的代码确实有它们,#pragma omp 可以替换为 // AWRBHAWRBWAQ 之类的东西。几乎任何注释都可以,只要它还没有出现在源代码中。 如果#pragma 已经被注释掉了,这将再次注释掉它,然后在clang-format 之后恢复它。 //#pragma omp 变为 ////#pragma omp,然后第二个 sed 将其还原为 //#pragma omp。但是,在第二个 sed 中,我看不出有任何理由使用 \/\/ *#pragma 而不是 \/\/#pragma 来匹配空格。 /g 似乎也没有必要,因为每行只有一个#pragma。所以我会做sed -i 's/\/\/#pragma omp/#pragma omp/' 您需要clang-format -i ./main.c 进行就地编辑,对吧?【参考方案4】:

通过手动检查各种 Clang 格式样式选项页面,我确定 as of Clang-format version 9,第三个(我认为最好的)选项出现了,称为 BeforeHash

注意:截至撰写本文时,Clang 12 已发布。有关当前发布的任何版本的最新 Clang 格式选项文档,请参阅此处:https://clang.llvm.org/docs/ClangFormatStyleOptions.html。

在您的.clang-format 文件中,您可以因此指定3 个选项,如下所示:

1。无缩进

IndentPPDirectives: None

例子:

#if FOO
#if BAR
#include <foo>
#endif
#endif

2。哈希后缩进 (#)

IndentPPDirectives: AfterHash

例子:

#if FOO
#  if BAR
#    include <foo>
#  endif
#endif

3。 (我认为最新和最好的选项——截至Clang-Format version 9 可用)哈希前缩进(#

IndentPPDirectives: BeforeHash

例子:

#if FOO
  #if BAR
    #include <foo>
  #endif
#endif

参考文献

对于所有这些文档,以及我上面使用的确切示例的来源,请参阅此处 LLVM Clang 格式样式选项官方文档的 IndentPPDirectives 部分:https://clang.llvm.org/docs/ClangFormatStyleOptions.html。

【讨论】:

【参考方案5】:

astyle(艺术风格)缩进 #pragma omp 与代码很好,开箱即用。甚至似乎没有改变行为的选项。只有续行不缩进,如示例中所示——我更喜欢在omp 下缩进续行,可能是 8 个空格。其他 pragma 左对齐。

void foo()

        #pragma omp parallel
#pragma omp master
    
#pragma omp task depend( some_expression ) \
            depend( other_expression ) \
    priority(1)
        
            code();
        
    

    #pragma other
    code();

变成

void foo()

    #pragma omp parallel
    #pragma omp master
    
        #pragma omp task depend( some_expression ) \
        depend( other_expression ) \
        priority(1)
        
            code();
        
    

#pragma other
    code();

有一个Astyle Visual Studio extension。

【讨论】:

以上是关于使用 clang 格式缩进预处理器指令的主要内容,如果未能解决你的问题,请参考以下文章

笔记3:预处理器-宏定义

预处理器指令

C#预处理器指令

预处理器的相关知识:

使用预处理器指令定义输出路径

dockerfile 语法