【问题标题】:Counting functions in C source codeC 源代码中的计数函数
【发布时间】:2013-09-19 08:27:09
【问题描述】:

我有完整的 C 项目,可以用 gcc 或 Visual Studio 构建。没有调用外部库。

我想知道那个项目有多少功能。

源代码中没有未使用的函数,并且该项目附带了使用不同参数运行它的测试,因此对于动态方法(例如运行时调用树),我需要在每次测试后累积结果。

是否有任何工具可以执行静态动态分析?

【问题讨论】:

  • 我确定您的代码正在调用标准 C 库中的函数(例如 printf...),因此您至少有一个外部库,即标准 C 库...
  • 嗯,实际上你不能确定这一点。这是一个复杂的计算引擎,并且尽可能有意地省略系统调用。就算有,也不过是5对2000,所以没关系。
  • 但是printf 不是系统调用。我的观点是,不使用标准库的可移植 C 应用程序代码(不是独立的)是无用的(除非它使用其他库),因为它无法进行任何输入或输出......

标签: c instrumentation


【解决方案1】:

gcc:

$ nm elf_file | grep "T " | grep -v " _" | wc -l

注意gcc 可以内联一些函数,即使优化被禁用,所以你应该编译:

-O0 -fno-builtin -fno-inline-functions-called-once

-finline-functions-called-once 默认启用,即使在-O0 中也是如此)

【讨论】:

  • 不是特定于 GCC,它特定于 ELF 文件......(以及许多 Linux 或其他 Unix 系统......)
  • @BasileStarynkevitch OP 在他的问题中提到了 gcc 和 Visual Studio,这不适用于 Visual Studio...
  • @ouah,好主意,这正是我所需要的。
【解决方案2】:

函数的定义可能并不像您想象的那么简单。特别是,C 源代码中的函数与生成的汇编代码中的函数不匹配,这主要是因为内联函数。

函数的数量和大小取决于优化级别和编译器。

许多标题(例如<stdio.h>)可能包含内联函数。如果不调用它们,编译器可能会通过不发出它们的代码来进行优化(某些静态函数也是如此)。很多时候,声明为 static inline 的函数不会出现在优化的代码中。

同样,一些宏可能会扩展为一些函数定义......

如果使用足够新的 GCC 版本(例如 4.7 或更高版本)进行编译,您可以为此目的制作一个简单的 MELT 扩展。最大的优点是它可以在 GCC 内部工作,因此可以真正计算 GCC 正在做什么......(例如,经过一些优化之后)。

请注意,GCC 可能会在优化期间生成或删除某些函数(function cloningfunction inlining....)

GCC MELT 自 2017 年起已过时

【讨论】:

    【解决方案3】:

    Frama-C 有一个metrics 插件,它可以计算程序中的函数数量。只需使用

    frama-c -metrics file1.c file2.c ... filen.c
    

    得到如下输出:

              Global metrics
          ============== 
          Sloc = 2080
          Decision point = 117
          Global variables = 51
          If = 117
          Loop = 22
          Goto = 75
          Assignment = 613
          Exit point = 242
          Function = 841
          Function call = 871
          Pointer dereferencing = 447
    

    【讨论】:

    • +1(我和 Virgile 在同一个实验室工作)很可能,Frama-C 不会例如内联函数,或删除死函数(例如那些提供的函数)通过在分析的源代码中碰巧没有用的系统头文件)。相反,优化编译器(如 GCC,甚至配备 MELT)会做到这一点。这实际上取决于 OP 想要测量的内容。
    • 事实上,Frama-C 会计算所有在源代码中定义或声明的函数(在链接之后,因此如果您在一个文件中有extern void f(void) 而在另一个文件中有void f() {},它将被计算一次。如果你想计算其他东西,你必须使用代码转换插件(或者如果现有的都没有你想要的,你自己编写)并在结果上使用metrics。跨度>
    【解决方案4】:

    您还可以使用 ctags 并解析标记文件。一种快速的方法是执行以下操作:

    ctags -R -f - . | grep -w f | wc -l
    

    在您项目的根目录中,但这可能并不总是正确的,例如,如果您在树的某处有这样的全局变量:

    int f;   
    

    【讨论】:

    • 在 ubuntu 中使用 exuberant-ctags 我可以使用 ctags -R --c-kinds=f -f - . | wc -l 对函数进行过滤,而不受 grep 方法的限制。
    【解决方案5】:

    C 源代码的静态分析工具是 Edison Design Group。它是编译器前端,您可以利用它来计算代码的各种指标。

    【讨论】:

      【解决方案6】:

      我有一个想法来计算函数 .c 文件。我们也可以计算这个 .java 文件。 这是 c# 类文件,您可以将文件传递给类

      class CountFunctions
      {
      
          private FileInfo File;
          private int functions = 0;
      
          public int getNumberOfFunctions
          {
              get { return functions; }
          }
      
          public countfunctions(FileInfo fs) {
              File = fs;
              getLineOfCode();
          }
      
          private void getLineOfCode()
          {
              string line;
              try
              {
                  StreamReader reader = File1.OpenText();
                  while (true)
                  {
                      line = reader.ReadLine();
      
                      if (IsFunction(line))
                      {
                          Functions++;
                      }
      
                      if (line == null)
                          break;
                  }
              }
              catch (Exception r)
              {
                  Console.WriteLine(r.Message);
              }
      
          }
      
          private bool IsFunction(string line)
          {
              if (line.Contains("void") || line.Contains("int") || line.Contains("short") || line.Contains("long") || line.Contains("float") || line.Contains("char") || line.Contains("double"))
              {
                  if (!line.Contains(";"))
                  {
                      return true;
                  }
              }
              return false;
          }
      } 
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-09-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多