C程序找到c文件的函数名

问题描述 投票:2回答:9

我正在使用C(Linux OS)进行编程。我必须读取一个文件,检查该文件中的函数并打印相应的函数名称。到目前为止,我已经编程使用'{'的深度计算来识别函数。我知道__FUNCTION__预处理器指令用于打印当前文件的函数名称。同样,是否有任何预处理器指令用于查找我们读取的文件的函数名称?我不关心任何具体的工具。我想让它编程。请指导我。提前致谢。

我试图实现这个代码。这个函数将行(在'{'之前)作为参数。

void ffname(char line[100])
{
    int i,j,m,n,f=0;
    char dt[10],fname[28];
    char s[5][10]={"int","void","struct","char","float"};
    dt = strtok(line," ");
    for(i=0;i<5;i++)
    {
        m=strcmp(dt,s[i]);
        if(m==0)
        {
            f=1;
            n=strlen(dt);
        }
    }
    if(f)
    {
        for(i=n+2,j=0;i<strlen(line);i++,j++)
        {
            if(line[i] == '*')
                i++;
            while(line[i] != '(')
            {
                fname[j]=line[i];
            }  
        }
    }
}

我不知道这段代码是否正确。我应该用这种方式吗?有找到功能名称的选项吗?

c function c-preprocessor preprocessor-directive
9个回答
3
投票

我假设您正在阅读的文件是C源文件。

如果你想要正确地做这件事,这不是一项微不足道的任务(意思是,如果你可靠地想要识别所有功能)。有关其他信息,请参阅Listing C/C++ functions (Code analysis in Unix)

我不关心任何具体的工具。我想让它编程。

这当然是可能的,但你基本上会得到C的扫描器/解析器前端,类似于DoxygenSynopsis等工具中已经实现的内容。您可以稍微简化一下并使用一些启发式方法,例如,您不需要解析完整的代码(例如,您可以跳过{}之间的任何内容)。

如果您仍想实现自己的方法,我会按照以下步骤操作:

  • 在任何情况下,您都应首先通过C预处理器运行C文件以解析任何宏并使原始C代码可用。
  • 然后熟悉基本的Compiler Construction技术,特别是扫描和Parsing你的源文件,以及C语法。请注意,根据您使用的C版本,有不同的语法。例如,ISO/IEC 9899:TC2, Annex A1包含C99的语法。查看上述工具的源代码也应该有所帮助。
  • 实现扫描程序以标记您的输入,并实现识别函数名称的解析器。从我之前提到的语法来看,(6.9.1) function-definition是你应该开始的生产术语。

2
投票

我使用Simple C代码来查找函数的名称。

#include <stdio.h>
#include <string.h>

#define SIZE 1024
void ffname(char *line)
{
    int i=1,j=0;
    char *dt; 
    char name[SIZE];
    strtok(line,"("); 
    dt = strchr(line,' '); 
    if(dt[i] == '*')
        i++;
    while(dt[i] != '\0')
    {
        name[j]=dt[i];
        i++;
        j++;
    }
    name[j] ='\0';
    printf("Function name is: %s\n", name);
}

int main(int argc, char **argv)
{
    if(argc < 2)
    {
        printf("Give the filename \n");
        printf("Usage: %s filename\n", argv[0]);
        return -1;
    }
    int i, lines =0, funlines =0,count =0, fn =0, flag =0;
    char c[SIZE],b[SIZE];
    FILE *fd;
    fd = fopen(argv[1],"r");
    while(fgets(c,SIZE,fd))
    {   
        lines++;
        i=0;
        for(i=0;i<strlen(c);i++)
        {
            while( c[i] =='\t' || c[i] == ' ')
            {
                i++;
            }
            if( c[i] == '{')
            {
                count++;
                if(flag)
                {
                    funlines++;
                }
                if(count == 1)
                {
                    fn++;
                    printf("Function %d is Started..............\n", fn); 
                    flag = 1;
                    ffname(b);
                }
                break;
            }
            else if( c[i] == '}')
            {
                count--;
                if(!count)
                { 
                    flag = 0;
                    printf("No of lines in the function %d is: %d\n", fn, funlines);
                    printf("Function %d is finished..........\n", fn);
                    funlines = 0;
                }
                else
                {
                    funlines++;
                }
                break;
            }
            else if(flag)
            {
                funlines++;
                break;
            }
        }
        strcpy(b,c);
    }
    printf("Total no of function%d\n",fn);
    printf("Total no of lines%d\n",lines);
    return 0;
}

1
投票

这很难正确完成。基本上,您需要实现一个c编译器来正确执行此操作。这正是c编译器所做的,并且需要正确的语法定义和预处理器来执行此操作。


1
投票

为C编写解析器很困难(并非不可能,很难),因为C支持如此多的语法。

您可以使用定义函数

  1. 标准C风格,带标准返回类型
  2. 标准C样式,带有typedef / enum等返回类型(使用简单的解析器无法轻松识别。您需要在文件中构建用户定义数据类型的数据库)
  3. C宏(例如参考Basile的answer
  4. 汇编(通过gcc -S解析一个非常简单的test.c来了解语法)我已经使用这个方法来创建一些占位符函数。

因此,您可以更轻松地解析程序集文件,而不是解析C文件。

例如。 gcc -S翻译C函数定义如下:

    .globl  someFnName
    .type   someFnName, @function
someFnName:
    ...function-body related code...

如果你只想要函数名列表(即不需要参数/返回值等),你可以轻松解析汇编中的上述3行代码,与C文件相比。 如果您还添加-g开关以及-s,您还可以获得一些行号信息。

好处:

  1. 比C文件更容易解析
  2. 处理大多数(如果不是全部)方法来定义函数。
  3. 根据“.globl someFnName”行是否存在,您可以隔离静态函数。

坏处:

  1. 需要外部解析器 - gcc或其他一些
  2. 需要编译器(gcc)依赖的辅助解析器
  3. 可能会有一些误报

1
投票

我认为flexbison将帮助您解决您的问题,这里有一些链接:c grammar(lex)c grammar(bison)


1
投票

简单的方法,如果你愿意做一些假设,请阅读源代码,然后:

  • 删除任何prerosessor指令(假设你不想要包含文件的函数,并且不想处理可能与函数相关的任何不稳定的#define宏,请注意多行#defines继续使用\在行尾)。
  • 删除任何评论(小心嵌套的/*评论)。
  • 将任何字符串转换为""(注意转义的\"和多行字符串)。
  • 将任何字符转换为' '或其他东西(摆脱'{'等,小心逃脱的\'以及其他逃脱)。
  • 将所有(嵌套,多行)代码块转换为“顶级”{}对。
  • 重新格式化文本,只有在;}之后才有换行符,除了将一行中的单个;连接到前一行,以防它实际上是};的一部分而不是函数定义。
  • 删除任何以;结尾的行

除非我错过了什么,现在你应该留下所有的函数定义,每行一个,函数体替换为{}


0
投票

我认为您可以尝试使用正则表达式来查找目标函数名称是否存在。

你可以在这篇文章中找到更多关于正则表达式Regular expressions in C: examples?


0
投票

你读了什么样的文件?它是一些任意的C源文件吗?如果是,它可以以许多不同的方式定义功能,例如,通过预处理器宏。例如用

#define DF(Nam) void Nam##print(void) {puts(#Nam);}

一个C文件可以有DF(foo)并定义了函数fooprint(源代码中没有出现任何fooprint)。

如果要处理编译器看到的函数名称集,可以更好地开发编译器扩展或插件。使用GCC,您可以使用MELT(一种特定于域的语言来扩展GCC)来实现此目的。

如果要查找某些目标文件*.o定义的[global]函数,可以在Linux上使用nm命令。也许还会考虑dlopen(3)-a共享对象文件*.so

当然,所有这些都可能是编译器和系统特定的。


0
投票

如果你可以使用gcc:

gcc -nostdinc -aux-info output demo.c

仅输出文件功能(不包括标准库)

注意:-nostdinc导致编译错误

您可以使用sed避免编译错误

gcc -aux-info output demo.c
sed '/include/d' output
© www.soinside.com 2019 - 2024. All rights reserved.