C语言 如何从源文件中提取单个函数

dfuffjeb  于 2023-04-29  发布在  其他
关注(0)|答案(6)|浏览(225)

我正在做一个关于extremely long and complicated functions in the Linux kernel的小型学术研究。我试图弄清楚是否有一个很好的理由写600或800行长的函数。
为此,我想找到一个工具,可以从一个函数中提取一个函数。c文件,这样我就可以对函数运行一些自动化测试。
例如,如果我在文件connect.c中有函数cifs_parse_mount_options(),我寻求的解决方案大致如下:

extract /fs/cifs/connect.c cifs_parse_mount_options

并返回523行代码(!),从左大括号到右大括号。
当然,任何操纵现有软件包(如gcc)来实现这一点的方法都是最有帮助的。
谢啦
乌迪

编辑:Regex to pull out C function prototype declarations?的答案让我相信,通过正则表达式匹配函数声明绝非易事。

vsikbqxv

vsikbqxv1#

你为什么不写一个小的Perl/PHP/Python脚本,甚至一个小的C++,Java或C#程序来做这件事呢?
我不知道有什么现成的工具可以做到这一点,但是编写代码来解析文本文件并从C++代码文件中提取函数体不应该超过20行代码。唯一困难的部分是定位函数的开始,这应该是一个相对简单的任务,使用RegEx。在此之后,您所需要的就是遍历文件的其余部分,跟踪左括号和右括号,当您到达函数体的右括号时,您就完成了。

7bsow1i6

7bsow1i62#

indent-kr代码-o代码。出局
awk -f分割。awk代码。输出
你必须适应一点点分裂。awk是我的代码和重构需求的特定部分(例如,我有一些不是typedef的struct
我相信你可以写一个更好的剧本:-)

--
BEGIN   { line=0; FS="";
    out=ARGV[ARGC-1]  ".out";
    var=ARGV[ARGC-1]  ".var";
    ext=ARGV[ARGC-1]  ".ext";
    def=ARGV[ARGC-1]  ".def";
    inc=ARGV[ARGC-1]  ".inc";
    typ=ARGV[ARGC-1]  ".typ";
    system ( rm " " -f " " out " " var " " ext " " def " " inc " " typ );
    }
/^[     ]*\/\/.*/   { print "comment :" $0 "\n"; print $0 >> out ; next ;}
/^#define.*/        { print "define :" $0 ; print $0 >>def ; next;}
/^#include.*/       { print "define :" $0 ; print $0 >>inc ; next;}
/^typedef.*{$/      { print "typedef var :" $0 "\n"; decl="typedef";print $0 >> typ;infile="typ";next;}
/^extern.*$/        { print "extern :" $0 "\n"; print $0 >> ext;infile="ext";next;}
/^[^    }].*{$/     { print "init var :" $0 "\n";decl="var";print $0 >> var; infile="vars";
                print $0;
                fout=gensub("^([^    \\*])*[    ]*([a-zA-A0-9_]*)\\[.*","\\2","g") ".vars";
                     print "var decl : " $0 "in file " fout;
                     print $0 >fout;
                next;
                        }
/^[^    }].*)$/     { print "func  :" $0 "\n";decl="func"; infile="func";
                print $0;
                fout=gensub("^.*[    \\*]([a-zA-A0-9_]*)[   ]*\\(.*","\\1","g") ".func";
                     print "function : " $0 "in file " fout;
                     print $0 >fout;
                next;
            }
/^}[    ]*$/        { print "end of " decl ":" $0 "\n"; 
                if(infile=="typ") {
                    print $0 >> typ;
                }else if (infile=="ext"){
                    print $0 >> ext;
                }else if (infile=="var") {
                    print $0 >> var;
                }else if ((infile=="func")||(infile=="vars")) {
                    print $0 >> fout; 
                    fflush (fout);
                    close (fout);
                }else if (infile=="def") {
                    print $0 >> def;
                }else if (infile=="inc"){
                    print $0 >> inc;
                }else print $0 >> out;
                next;
            }
/^[a-zA-Z_]/        { print "extern :" $0 "\n"; print $0 >> var;infile="var";next;}
            { print "other :" $0 "\n" ; 
                if(infile=="typ") {
                    print $0 >> typ;
                }else if (infile=="ext"){
                    print $0 >> ext;
                }else if (infile=="var") {
                    print $0 >> var;
                }else if ((infile=="func")||(infile=="vars")){
                    print $0 >> fout;
                }else if (infile=="def") {
                    print $0 >> def;
                }else if (infile=="inc"){
                    print $0 >> inc;
                }else print $0 >> out;
               next;
               }
3wabscal

3wabscal3#

如果您发现难以提取函数名:
1〉使用ctags(一个程序)提取函数名。ctags -x --c-kinds=fp path_to_file。2〉一旦你得到了函数名,写一个简单的Perl脚本,通过传递函数的脚本名来提取函数的内容,如上所述。

fkvaft9z

fkvaft9z4#

Bash内置declare似乎提供了类似的功能,但我不确定它是如何实现的。特别地,declare -f列出了当前环境中的函数:

declare -f quote
declare -f quote_readline

declare输出当前环境中的函数列表:

quote () 
{ 
    local quoted=${1//\'/\'\\\'\'};
    printf "'%s'" "$quoted"
}
quote_readline () 
{ 
    local ret;
    _quote_readline_by_ref "$1" ret;
    printf %s "$ret"
}

最后,declare -f quote输出quote函数的函数定义。

quote () 
{ 
    local quoted=${1//\'/\'\\\'\'};
    printf "'%s'" "$quoted"
}

也许底层的机制可以被重新利用来满足你的需求。

2wnc66cl

2wnc66cl5#

你应该使用像clang这样的东西,它实际上会解析你的源代码,并允许你分析它。因此,它可以在许多语言中找到函数,即使你考虑宏。你没有机会使用正则表达式。

ngynwnxp

ngynwnxp6#

我有一个类似的需求,从C代码中提取一个函数,我发现vim(编辑器)适合我的需求(而且更容易),因为我不必编写任何外部工具或依赖不可靠的正则表达式,这可能会变得乏味。
测试代码:

$ cat -n c.c
   1 #include <stdio.h>
   2 static int
   3 testme (void)
   4 {
   5     int i=1;
   6 
   7     if (i == 1) {
   8           printf("\nDo something\n");
   9     }
  10     return 0;
  11 }
  12 
  13 int main (int argc, char *argv[])
  14 {
  15     testme();
  16     return 0;
  17 }

在非交互(ex)模式下使用vim-es
step.1 -使用vim搜索到函数的开头(假设函数名在行的开头,后面跟着空格-+/<function-name>,然后打印行号-!echo line(".")
step.2 -移动到 * 行首 * 的下一个右括号-+/}并打印行号
step.3 -退出文件-+q
step.4 -现在我们有了一个 start-line#end-line# -我们将以<start>,<end>p的形式将其管道传输到sed(在调用sed之前,需要对paste进行一点按摩)以转储整个函数。
完整命令:

$ vim -es c.c +/'testme ' +'exec(":!echo ".line("."))'  +'/^}'  +'exec(":!echo ".line("."))'  +q | paste -sd "," - | xargs -i{} sed -n {}p c.c
testme (void)
{
    int i=1;

    if (i == 1) {
          printf("\nDo something\n");
    }
    return 0;
}

相关问题