Search code examples
gccvimctags

Is ctags support fixed prototype function of GCC?


I found that gcc support a strange function definition like:

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

Which compile with -D__USE_FIXED_PROTOTYPES__. And my taglist plugins of vim couldn't give correct result. I tried to figure out in man page of ctags but I couldn't find it.

EDIT Yes, this is strange. The macro is

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

and the comment tells that this is

ANSI/K&R compatibility stuff.

It's intend to suite xlc, the c compiler of AIX.


Solution

  • With the macro definition as shown:

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

    this declaration:

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

    (I've added a trailing semicolon) expands to this:

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

    which is a perfectly ordinary function prototype (assuming a trailing semicolon).

    There's probably an alternate version of that macro, something like this:

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

    that would expand to:

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

    which is a K&R-style non-prototype function declaration.

    Likely there's something like:

    #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
    

    along with similar macros P0, P1, P2, etc., for different numbers of parameters. Or perhaps, as you imply in your question, it uses a user-defined macro __USE_FIXED_PROTOTYPES__ rather than __STDC__.

    This would allow a single declaration to automatically expand either to a modern prototype or to a K&R-style declaration; the latter would be necessary only with very old pre-ANSI compilers.

    To answer the question in the title (finally!), ctags operates on non-preprocessed C source. A quick experiment with the GNU ctags shows that it's not particularly clever about interpreting macros that obscure the basic syntax. It will generate tag entries for the macro definitions themselves, but it won't recognize

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

    as a function definition. (You could run the source file through the preprocessor, but then the tags would refer to the preprocessed file, which is not particularly useful.) In principle, ctags should understand the complete C syntax, including the preprocessor; in practice, it doesn't.

    If you want to have ctags generate tags for your source file, you'll need to get rid of the macros and write recognizable prototypes. You won't be able to compile the modified source with a pre-ANSI compiler, but these days that's very unlikely to be a problem. If you're in a position to do this, the resulting code should be easier to maintain.

    Or, since the output generated by ctags is reasonably simple, it shouldn't be too difficult to manually add the relevant tags to the tags file (though maintaining it automatically could be difficult).