带你走进Cflow (一)

news/2024/5/17 16:26:14 标签: 算法, 图论, cflow, java, gitee, spring

目录

​编辑

cflow%20%E7%AE%80%E4%BB%8B-toc" style="margin-left:40px;">1、cflow 简介

cflow%20%E5%88%86%E6%9E%90%E7%A8%8B%E5%BA%8F%E7%9A%84%E7%AE%80%E8%A6%81%E6%96%B9%E6%B3%95-toc" style="margin-left:40px;">2、使用 cflow 分析程序的简要方法

3、两种类型的流图


cflow%20%E7%AE%80%E4%BB%8B" style="background-color:transparent;">1、cflow 简介

        cflow 工具用于分析 C 语言实现的源文件集并输出各个函数之间的依赖关系图。cflow 可以生成两种类型的图:正向图和逆向图。正向图从 main()函数开始,递归显示 main()函数调用的所有函数。相反,逆向图是一个子图的集合,使用递归命令时,为每个函数列出它的调用者。

        除了这两种输出模式,cflow 也可以为输入文件中的所有遇到的符号生成一个交叉引用列表。

        该程序还提供了对将出现在输出中出现的符号的详细控制,允许忽略用户不感兴趣的符号。详细的输出格式也是可配置的。

cflow%20%E5%88%86%E6%9E%90%E7%A8%8B%E5%BA%8F%E7%9A%84%E7%AE%80%E8%A6%81%E6%96%B9%E6%B3%95">2、使用 cflow 分析程序的简要方法

        我们先从一个例子开始熟悉 GNU cflow 的用法。假设你已经有了一个 whoami命令的简单实现,并且你想获得它的函数依赖关系图。下面的是程序:

 #include <pwd.h>
 #include <sys/types.h>
 #include <stdio.h>
 #include <stdlib.h>
 
 int
 who_am_i (void)
 {
 struct passwd *pw;
 char *user = NULL;
 
 pw = getpwuid (geteuid ());
 if (pw)
 user = pw->pw_name;
 else if ((user = getenv ("USER")) == NULL)
 {
fprintf (stderr, "I don't know!\n");
 return 1;
 }
 printf ("%s\n", user);
 return 0;
 }
 
 int
 main (int argc, char **argv)
 {
 if (argc > 1)
 {
 fprintf (stderr, "usage: whoami\n");
 return 1;
 }
 return who_am_i ();
 }

运行 cflow 产生下面的输出:

$ cflow whoami.c
 main() <int main (int argc,char **argv) at whoami.c:26>:
 fprintf()
 who_am_i() <int who_am_i (void) at whoami.c:8>:
 getpwuid()
 geteuid()
 getenv()
 fprintf()
 printf()

        这是一个正向调用图显示了输入文件中的调用者-被调用者依赖关系。每一行以一个函数名开始,紧跟后面有一对括号来指明这是一个函数。如果这个函数在某一个输入文件中定义,这一行会使用一对尖括号,其中显示函数的原型和它被定义的位置。这一行将会以:结尾来表示这个函数调用了其它函数。比如,这一行main() <int main (int argc,char **argv) at whoami.c:25>:显示 main 函数在源文件 whoami.c 中的第 25 行定义,原型是 int main (intargc,char **argv),最后的冒号表示 main 函数调用了其他函数。这一行后面的是被 main 函数调用的函数。每一行都会根据嵌套关系有相应的缩进。

        通常 cflow 会显示完整的函数原型。然而有时你希望忽略原型的一部分。一些选项可以用来完成这个功能。使用--omit-symbol-names 选项来打印没有函数名的原型。使用--omit-arguments 选项来忽略参数列表。这些选项可以被用做很多用途,其中一个就是使结果图更加的紧凑。为了显示他们的作用,下面是使用上述两种--omit-选项的结果:main() <int () at whoami.c:25>:默认情况下,cflow 从 main()函数开始输出正向图。当分析一个完整的 C 程序集的时候这是非常的便利的。但是有时候用户可能只想看到从特定函数出发的部分图。使用—main(-m)选项,Cflow 允许选择这样的功能调用。因此,运行$cflow--main who_am_i whoami.c,将会得到下面的结果:

who_am_i() <int who_am_i (void) at whoami.c:8>:
 getpwuid()
 geteuid()
 getenv()
 fprintf()
 printf()

3、两种类型的流图

        在前面我们讨论了正向图,用于展示调用者-被调用者的依赖关系。另一种 cflow输出是逆向图,列举被调用者-调用者的依赖关系。,为了生成逆向图,运行 cflow的时候要使用--reverse(-r)选项。比如使用下面的例子:

 fprintf():
     who_am_i() <int who_am_i (void) at whoami.c:8>:
         main() <int main (int argc,char **argv) at whoami.c:26>
     main() <int main (int argc,char **argv) at whoami.c:26>
 getenv():
     who_am_i() <int who_am_i (void) at whoami.c:8>:
         main() <int main (int argc,char **argv) at whoami.c:26>
 geteuid():
     who_am_i() <int who_am_i (void) at whoami.c:8>:
         main() <int main (int argc,char **argv) at whoami.c:26>
 getpwuid():
     who_am_i() <int who_am_i (void) at whoami.c:8>:
         main() <int main (int argc,char **argv) at whoami.c:26>
 main() <int main (int argc,char **argv) at whoami.c:26>
 printf():
     who_am_i() <int who_am_i (void) at whoami.c:8>:
         main() <int main (int argc,char **argv) at whoami.c:26>
     who_am_i() <int who_am_i (void) at whoami.c:8>:
 main() <int main (int argc,char **argv) at whoami.c:26>

        这个输出包含了几个子图,每一个字图描述了一个特定的函数的调用者。因此,第一个子图说明函数 fprintf 被两个函数调用:who_am_i 和 main。同时他也被 main函数直接调用。

        第一个值得注意的地方是在输出中 who_am_i 重复出现了多次。这是一个详细的输出,为了让输出显得更加简洁,可以使用--brief(-b)选项。比如:

$ cflow --brief --reverse whoami.c
 fprintf():
 who_am_i() <int who_am_i (void) at whoami.c:8>:
 main() <int main (int argc,char **argv) at whoami.c:26>
 main() <int main (int argc,char **argv) at whoami.c:26> [see 3]
 getenv():
 who_am_i() <int who_am_i (void) at whoami.c:8>: [see 2]
 geteuid():
 who_am_i() <int who_am_i (void) at whoami.c:8>: [see 2]
 getpwuid():
 who_am_i() <int who_am_i (void) at whoami.c:8>: [see 2]
 main() <int main (int argc,char **argv) at whoami.c:26> [see 3]
 printf():
 who_am_i() <int who_am_i (void) at whoami.c:8>: [see 2]
 who_am_i() <int who_am_i (void) at whoami.c:8>: [see 2]

        在简要输出中,一旦某个给定的函数被写入,随后的关于该函数的调用实例中将会只包含它的定义和第一次输出行的引用。

        如果输出图比较大,查找需要的行数就会比较麻烦(除非你使用 Emacs 的cflow-mode)。这种情况下可以使用特殊的选项--number (-n),这样就可以在输出时显示每一行的顺序标号。使用这个选项,上面的输出将变成这样:

$ cflow --number --brief --reverse whoami.c
 1 fprintf():
 2 who_am_i() <int who_am_i (void) at whoami.c:8>:
 3 main() <int main (int argc,char **argv) at whoami.c:26>
 4 main() <int main (int argc,char **argv) at whoami.c:26> [see 3]
 5 getenv():
 6 who_am_i() <int who_am_i (void) at whoami.c:8>: [see 2]
 7 geteuid():
 8 who_am_i() <int who_am_i (void) at whoami.c:8>: [see 2]
 9 getpwuid():
 10 who_am_i() <int who_am_i (void) at whoami.c:8>: [see 2]
 11 main() <int main (int argc,char **argv) at whoami.c:26> [see 3]
 12 printf():
 13 who_am_i() <int who_am_i (void) at whoami.c:8>: [see 2]
 14 who_am_i() <int who_am_i (void) at whoami.c:8>: [see 2]

        当然,--brief 和--number 选项对正向图和逆向图都起作用。


http://www.niftyadmin.cn/n/5166828.html

相关文章

【每日一题】咒语和药水的成功对数

文章目录 Tag题目来源解题思路方法一&#xff1a;排序二分 写在最后 Tag 【排序二分】【数组】【2023-11-10】 题目来源 2300. 咒语和药水的成功对数 解题思路 方法一&#xff1a;排序二分 我们首先对 points 进行升序排序&#xff0c;然后枚举 spells 中的 x&#xff0c;需…

企业微信开发教程一:添加企微应用流程图解以及常见问题图文说明

最近在前辈的基础上新添加了一个企微应用&#xff0c;过程中遇到了一些卡点&#xff0c;这里一一通过图片标注与注释的方式记录一下&#xff0c;希望能给后来人提供一些清晰明了的帮助&#xff0c;话不多说&#xff0c;大家直接看图吧。 &#xff08;文中包括一些本项目独有的配…

大语言模型-LLM简介

大语言模型如此火爆&#xff0c;查了些资料整理一下&#xff0c;做个初步的了解。 语言模型的发展从开始的统计方法到使用神经网络&#xff0c;再到现在通过使用Transformer架构的模型训练大量数据&#xff0c;理解文本规则和模式&#xff0c;同时随着训练数据和模型的扩大&…

Linux每日智囊

每日分享三个Linux命令&#xff0c;悄悄培养读者的Linux技能。 man 作用 查看帮助手册 语法 man [参数] 参数&#xff1a; -f:显示给定关键字的简短描述信息 -k:根据关键词搜索帮助手册 -w: 显示手册文件所在位置 案例 1.查看命令手册 man man查看命令手册的快捷键…

Spring-推断构造方法

Spring中的Bean实例化对象&#xff0c;需要构造方法 通常一个类只有一个构造方法&#xff1a; 1、无参的构造方法&#xff0c;实例化只能选择这一个 2、有参的构造方法 使用AnnotationConfigApplicationContext&#xff0c;会使用这个构造方法进行实例化&#xff0c;Spring根…

实验语音学的基本概念

语音学 实验语音学只是语音学的一个分支&#xff0c;那么语音学到底是研究什么的呢&#xff1f;我们先有一个大致了解。 语音学是研究语言声音体系的学科。语音学的任务是研究说明语音的性质&#xff0c;内部结构和单位&#xff0c;语音的分类和组合&#xff0c;语音的产生、…

图像二值化阈值调整——Triangle算法,Maxentropy方法

一. Triangle方法 算法描述&#xff1a;三角法求分割阈值最早见于Zack的论文《Automatic measurement of sister chromatid exchange frequency》主要是用于染色体的研究&#xff0c;该方法是使用直方图数据&#xff0c;基于纯几何方法来寻找最佳阈值&#xff0c;它的成立条件…

linux - 日志

目录 log.h log.c log.demo.c 运行演示 log.h #ifndef LOG_H #define LOG_H /* ************************************************************************************ */#include <dirent.h> #include <errno.h> #include <fcntl.h> #include <ma…