【问题标题】:ctags chokes on source file with unbalanced braces due to #ifdef由于#ifdef,ctags 在带有不平衡大括号的源文件上阻塞
【发布时间】:2011-03-13 12:39:13
【问题描述】:

我正在使用ctags 为我正在处理的C 项目生成tags 文件,但文件中缺少许多函数。这似乎是由于使用#ifdef 导致源文件中的大括号不平衡造成的。一个(简化的)例子:

#include <stdio.h>

struct mystruct {
        long member;
#ifndef _MSC_VER
}__attribute__ ((packed));
#else /* _MSC_VER */
};
#pragma pack(pop)
#endif /* _MSC_VER */

char* greeting_text(){
  return "Hello world\n";
}

int main( int argc, const char* argv[] ){
  char * greeting = greeting_text();
  printf(greeting);
  return 0;
}

这可以在 Linux 下与 gcc -Wall 完美编译和工作。但是,如果我使用 ctags problem.c 解析它,tags 文件只包含 mystruct 的条目——缺少这些函数。

ctags --verbose 报告:

OPENING problem.c as C language file
problem.c: unexpected closing brace at line 8
problem.c: retrying file with fallback brace matching algorithm
OPENING problem.c as C language file
problem.c: unexpected closing brace at line 8

显然ctags 不喜欢文件中的预处理器技巧。

有没有办法让ctags 处理这个问题?

ctags 的手册页甚至明确提到了这个问题,但表明ctags 可以解决这个问题。但是,这似乎不起作用...

这是 Exuberant Ctags 5.8(Debian 软件包 1:5.8-4)。

编辑:

我也对处理这类结构的 ctags 的替代品感兴趣。

【问题讨论】:

    标签: c c-preprocessor ctags exuberant-ctags


    【解决方案1】:

    由于 ctags 的问题,我最终改用cscope

    虽然它并不完美,但它比 ctags 更好地处理宏,并且它可以像 ctags 一样与 vim 集成(参见 http://vimdoc.sourceforge.net/htmldoc/if_cscop.html#:cscope)。

    【讨论】:

      【解决方案2】:

      在将文件提供给 ctags 之前,我会尝试对文件运行预处理器 (gcc -E)。这是否会产生一个好的结果我不确定,但值得一试。当然,您的代码的所有组件都应该出现,但是 ctags 会识别 gcc 在输出中留下的其他文件引用吗?不确定。

      【讨论】:

      • 好主意。但是,问题是ctags处理的中间文件中的行号将与原始源文件中的行号不同,因此使用ctags跳转到正确的行可能不起作用。不过,我会试一试。
      • 另外,这还会生成将.h.c 文件组合在一个文件中的文件,因此不清楚 ctags 应该如何找到要跳转到的原始源文件(因为它可能是.c 文件或包含的.h 文件之一)。我会看到...
      • 预处理器输出应该包含指示源块来自哪些文件和行的指令。 ctags 是否会尊重这些是个问题。
      • 进一步看,我看到 ctags 有一个选项 −−line−directives,这似乎是专门用于 ctags 可以成功处理每个处理器的输出,并且仍然可以在原始源文件中找到这些行。也许这实际上会起作用......
      【解决方案3】:

      您可以尝试重写代码,以便只有一个右大括号,例如:

      struct mystruct {
              long member;
      }
      #ifndef _MSC_VER
      __attribute__ ((packed))
      #endif
      ;
      #ifdef _MSC_VER
      #pragma pack(pop)
      #endif /* _MSC_VER */
      

      当然,您可以定义一些方便的宏来使其更易于阅读。

      【讨论】:

      • 我当然可以重写代码,但这不是我的项目,我必须在几十个地方重写代码。我认为这不是解决 ctags 中的错误/缺陷的好方法。
      【解决方案4】:

      您可以运行unifdef 工具来选择性地(临时)用空行(unifdef -l -U_MSC_VER) 替换代码的非活动部分。结果是

      #include <stdio.h>
      
      struct mystruct {
              long member;
      
      }__attribute__ ((packed));
      
      
      
      
      
      char* greeting_text(){
        return "Hello world\n";
      }
      
      int main( int argc, const char* argv[] ){
        char * greeting = greeting_text();
        printf(greeting);
        return 0;
      }
      

      Ctags 正确解析它没有问题,并且行号保持不变(如果您按行号创建 ctags 搜索,这很重要):

      $ cat tags
      !_TAG_FILE_FORMAT       2       /extended format; --format=1 will not append ;" to lines/
      !_TAG_FILE_SORTED       1       /0=unsorted, 1=sorted, 2=foldcase/
      !_TAG_PROGRAM_AUTHOR    Darren Hiebert  /dhiebert@users.sourceforge.net/
      !_TAG_PROGRAM_NAME      Exuberant Ctags //
      !_TAG_PROGRAM_URL       http://ctags.sourceforge.net    /official site/
      !_TAG_PROGRAM_VERSION   5.6     //
      greeting_text   y.c     /^char* greeting_text(){$/;"    f
      main    y.c     /^int main( int argc, const char* argv[] ){$/;" f
      member  y.c     /^        long member;$/;"      m       struct:mystruct file:
      mystruct        y.c     /^struct mystruct {$/;" s       file:
      

      unifdef 在许多操作系统上都可以作为一个软件包使用(例如 FreeBSD、各种 Linux 发行版、Cygwin)。主页:http://dotat.at/prog/unifdef/

      【讨论】:

      • 有趣的想法(和有趣的工具)。这是你的意思的“unifdef”:dotat.at/prog/unifdef
      • @sleske 是的;它可以作为一个包在许多操作系统上使用(例如 FreeBSD、各种 Linux 发行版、Cygwin)。
      • @sleske 请注意,那里有几个版本。有些人使用-b 而不是-l 来替换空行。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-06-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多