Extracting C / C++ function prototypes

Viewed 21930

I want to do this:

extract_prototypes file1.c file2.cpp file3.c

and have whatever script/program print a nice list of function prototypes for all functions defined in the given C / C++ files. It must handle multi-line declarations nicely.

Is there a program that can do this job? The simpler the better.

EDIT: after trying to compile two C programs, bonus points for something that uses {perl, python, ruby}.

11 Answers

I use ctags and jq

ctags --output-format=json --totals=no --extras=-F --fields=nP file1.c |
jq -sr 'sort_by(.line) | .[].pattern | ltrimstr("/^") | rtrimstr("$/") | . + ";"'

If you have universal-ctags (https://ctags.io), --_xformat option may be useful though you need sed and tr commands to get what you want.

$ cat input.c 
struct object *new_object (struct
                           /* COMMENT */
                           param
                           /* IGNORE ME */
                           *p)
{
    return NULL;
}
int main (void)
{
    return 0;
}
$ ./ctags -o - --kinds-C=f --kinds-C++=f -x --_xformat='%{typeref} %{name} %{signature};' input.c | tr ':' ' ' | sed -e 's/^typename //'
struct object * new_object (struct param * p);
int main (void);
$

This is similar to the answer posted by Steve Ward but this one requires sed, and tr instead of jq.

In more modern versions of GCC, you can also use -aux-info to get this information when writing C code. See here.

Here's a sample of what the output looks like:

/* src/main.c:30:NC */ static void usage (const char *);
/* src/main.c:32:NF */ extern int main (int argc, char **argv); /* (argc, argv) int argc; char **argv; */
/* src/main.c:57:NF */ static void usage (const char *prog_name); /* (prog_name) const char *prog_name; */

You can run the source file through this program:

/* cproto_parser.c */
#include <stdio.h>                           
int main (void)                              
{                                            
    int c;                                   
    int infundef = 0;                        
    int nb = 0,                              
        np = 0;                              
    while((c=getc(stdin))!=EOF){             
        if(c=='{'){                          
            if((np==0)&&(nb==0)){infundef=1;}
            nb++;                            
        }                                    
        if (infundef==0) {putc(c,stdout);}   
        if(c=='}'){                          
            if((np==0)&&(nb==1)){infundef=0;}
            nb--;                            
        }                                    
        if(c=='('){np++;}                    
        if(c==')'){np--;}                    
    }                                        
    return 0;                                
}                    

Run through the preprocessor to get rid of comments. If you have unmatched braces due to #ifdefs you have to set defines, include files to make it not so.

e.g., cc cproto_parser.c -o cproto_parser; cc -E your_source_file.c|./cproto_parser

Related