【问题标题】:How to Get Emacs to Properly Handle C Preprocessor Conditionals如何让 Emacs 正确处理 C 预处理器条件
【发布时间】:2012-03-26 16:14:54
【问题描述】:

我有一个性能敏感的 CUDA 代码,我正在使用它

#ifdef DEBUG_<NAME_OF_SECTION>
   ...
#else
   ...
#endif

...封装速度严重的调试代码的条件,它会从 GPU 中获取额外的信息。

在 emacs (Centos 6.0) 中一切顺利,直到 #else

这将取消缩进(通过 1 个选项卡)预处理器条件的 else 子句中的文本,然后继续取消缩进所有内容。

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 注意: ) 预处理器条件中的复制似乎由 C 模式正确处理。但是); 重复会破坏事情,迫使您将); 移到条件之外......哦,天哪,多么不一致。在我们获得适当的 elisp 代码来解决这种不一致之前,我一直保持这个问题的开放性。 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

关于当前答案的注意事项:
Jens 提供了不准确的信息,声称在条件句中缩进嵌套的 ) 是“不可能的”。这不仅是可能的,而且 Emacs 的 C-Mode 也积极地做到了这一点。请注意此问题帖子末尾示例 c 程序的正确缩进,以证明这一点。因此,); 也可以缩进是有道理的,尽管出于Jens 概述的原因应谨慎行事。

无论如何,我想确保人们看到这个陈述是不正确的,所以他们不认为这个问题是无法回答的。当 Jens 修改他的不准确陈述以反映这是可能的时,我将删除这条评论和我对 Jens 帖子的反对票,在他概述的 ) 的情况下以 C 模式实现,但不推荐。

目前我正在诉诸手动将内容向前一个选项卡重新间隔,但这会浪费很多时间(代码很长)。

知道我可以在 ~/.emacs 文件中添加什么来解决这个问题吗???

提前致谢!

编辑 1 我应该提到它似乎窒息的子句是一个函数关闭,例如

      MyFunc<<<Blk,Thr>>>(Stuff1,
  #ifdef DEBUG_FUNC1
                          Stuff2,
                          dev_Debug);
  #else
                       Stuff2); //Deindents here.
  #endif
  //Everything here on out is deindented.

这可能是这种代码结构的特定故障...

编辑 2 这是一个简单的 C 代码版本...代码按预期工作,但不是最后一个 #else 子句的缩进...

#include <stdio.h>

//#define DEBUG

void printer
(int A,
#ifdef DEBUG
 int B,
 int C)
#else
 int B)
#endif
{
#ifdef DEBUG
   printf("A: %i, B: %i, C: %i\n", A, B, C);
#else
   printf("A: %i, B: %i\n", A, B);
#endif
}

int main()
{
   int A = -3;
   int B = 1;
   int C = 3;
   printer(A,
#ifdef DEBUG
       B,
       C);
#else
   B);
#endif
   return 0;
}

...这与我正在做的事情一致。我知道它在 C 中的语法上工作(或者至少我认为......它给出了正确的结果),但是 emacs 不喜欢函数调用中的 #else 子句......

【问题讨论】:

  • 如果你计算#ifdef#else之间的代码中的左大括号和右大括号({})的个数,它们都匹配吗?
  • 查看示例...在它阻塞的预处理器部分中没有{}...。似乎不喜欢我在函数调用中使用预处理器 else 。发布一个非 CUDA 示例,以便说明我的意思...
  • 考虑在每个分支中添加更多(例如,如果需要,重复定义)。我怀疑这是由于第一条路径中的“)”。
  • 花括号或方括号([])或括号,没关系,它必须匹配打开和关闭的数量。 Emacs C 和 C++ 模式在某种程度上是愚蠢的,它们并没有像 MS Visual Studio 那样真正解析缓冲区中的代码。因此,诸如您所拥有的结构将使 Emacs 缩进错误。
  • @Joachim ...虽然我同意你的看法,但基于上述经验,emacs C 模式在某些情况下是愚蠢的(因为它破坏了我的有效语法,但接受下面 Jens 提出的替代等效语法)。也就是说,我正在格式化的代码是由 VS 中的一位同事完成的,并且格式化是非常糟糕的制表符。 Emacs 可能无法正确处理所有内容,但根据我的经验,至少它的格式适合窄默认宽度、轻量级 Linux 样式编辑器——在这方面比 VS 更好。

标签: c emacs editor elisp code-formatting


【解决方案1】:

我认为问题出在代码的逻辑上。从逻辑上讲,函数参数列表中有不同的参数。右括号不应该是条件的一部分。

 MyFunc<<<Blk,Thr>>>(
                      Stuff1,
 #ifdef DEBUG_FUNC1
                      Stuff2,
                      dev_Debug
 #else
                      Stuff2
 #endif
                      );

或者,您应该有两个完整版本的原型,根据您的调试宏选择。其他所有内容不仅难以为 emacs(或可能任何其他编辑器)解析,而且对于你之后的可怜人来说也是如此。

你想要的是不可能的,因为代码的缩进级别可能取决于宏:

#if A
(
#endif
something
#if B
)
#endif

其中AB 对于所有有效编译都是相同的。如果不假设 AB 的值,Emacs 无法知道如何缩进。

【讨论】:

  • 我的代码在语法上是正确的并且可以编译......它可能是错误的形式,但我在每个结束的 arg 集上都包含一个 ); 上限。不把这变成关于编码标准的辩论,如果它在语法上是正确的,为什么不能省略处理它。
  • 如果您不相信语法的工作原理,请参阅上面的简单 C 示例。现在,您的解决方案确实有效,但我想尝试回答为什么 emacs c 处理程序屠宰我的替代方案,但有效的语法以及如何防止这种情况......直到我得到答案,这个问题仍然悬而未决原则,但我正在评价你,因为我正在使用你的解决方案作为解决方法。 ;)
  • @Jason,因为 elisp 是 lisp。它的解析器非常依赖于扫描右括号(广义上)。 C 是不同的,它分阶段解析代码并在语法上替换(或消除)部分文本。不知何故,您希望识别预处理器宏的任何可能值的代码。对于给定的 blob,无法保证以这种方式计算的缩进甚至是唯一的。
  • @Jason:编辑由有权查看suggested edits queue 的用户审核。 两个 人拒绝了您的编辑:stackoverflow.com/suggested-edits/217376(我也投了reject 投票,但我为时已晚——另外两个人击败了我)。不要试图通过编辑来回复问题或答案; the original wiki used that approach,它使除作者之外的所有人都无法阅读整个网站。作为对问题的编辑,您的编辑会更有意义。
  • 编辑问题后,您可以评论人们的答案以提醒他们进行了编辑。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-04-29
  • 1970-01-01
  • 2014-08-02
  • 1970-01-01
相关资源
最近更新 更多