1

我发现 gcc 支持一个奇怪的函数定义,例如:

static void add_define P3(char *, name, int, nargs, char *, exps)

使用 -D__USE_FIXED_PROTOTYPES__ 编译。而且我的 vim taglist 插件无法给出正确的结果。我试图在 ctags 的手册页中找出答案,但找不到。

编辑 是的,这很奇怪。宏是

#define P3(t1, v1, t2, v2, t3, v3) (t1 v1, t2 v2, t3 v3)

并且评论告诉这是

ANSI/K&R 兼容性的东西。

它打算与 AIX 的 c 编译器 xlc 配套。

4

1 回答 1

4

使用如图所示的宏定义:

#define P3(t1, v1, t2, v2, t3, v3) (t1 v1, t2 v2, t3 v3)

这个声明:

static void add_define P3(char *, name, int, nargs, char *, exps);

(我添加了一个尾随分号)扩展为:

static void add_define(char *name, int nargs, char *exps);

这是一个完全普通的函数原型(假设尾随分号)。

该宏可能有另一个版本,如下所示:

#define P3(t1, v1, t2, v2, t3, v3) \
    (v1, v2, v3) \
    t1 v1; \
    t2 v2; \
    t3 v3;

这将扩展到:

static void add_define(name, nargs, exps)
char *name;
int nargs;
char *exps

这是一个 K&R 风格的非原型函数声明。

可能有类似的东西:

#ifdef __STDC__
#define P3(t1, v1, t2, v2, t3, v3) (t1 v1, t2 v2, t3 v3)
#else
#define P3(t1, v1, t2, v2, t3, v3) \
    (v1, v2, v3) \
    t1 v1; \
    t2 v2; \
    t3 v3;
#endif

以及类似的宏 P0、P1、P2 等,用于不同数量的参数。或者,正如您在问题中暗示的那样,它使用用户定义的宏__USE_FIXED_PROTOTYPES__而不是__STDC__.

这将允许单个声明自动扩展为现代原型或 K&R 样式的声明;后者只有非常旧的 ANSI 前编译器才需要。

要回答标题中的问题(终于!),ctags对未预处理的 C 源代码进行操作。对 GNU 的快速实验ctags表明,它在解释模糊基本语法的宏方面并不是特别聪明。它将为宏定义本身生成标签条目,但它不会识别

static void add_define P3(char *, name, int, nargs, char *, exps) {
    /* ... */
}

作为函数定义。(你可以通过预处理器运行源文件,但是标签会引用预处理文件,这不是特别有用。)原则上ctags 应该理解完整的C语法,包括预处理器;在实践中,它没有。

如果你想ctags为你的源文件生成标签,你需要摆脱宏并编写可识别的原型。您将无法使用 pre-ANSI 编译器编译修改后的源代码,但现在这不太可能成为问题。如果您能够做到这一点,那么生成的代码应该更容易维护。

或者,由于 生成的输出ctags相当简单,手动将相关标签添加到tags文件中应该不会太困难(尽管自动维护它可能很困难)。

于 2012-12-23T05:14:49.967 回答