使用如图所示的宏定义:
#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
文件中应该不会太困难(尽管自动维护它可能很困难)。