上次的Hello world算是入门了,现在学习一些相关工具的使用
写好程序,首先要编译,就用gcc就好了,基本用法如下
helloworld.c是源码,helloworld.o是编译后的可执行文件,运行的话就用 ./helloworld.o
就可以了。
但是如果代码写的多了,每次改动完都手动用gcc编译太麻烦了,所以要用Makefile来 自动化这项工作,在当前目录下创建Makefile文件,大概如下
缩进为0每一行表示一个任务,冒号左边的是目标文件名,冒号后面是生成该目标的依赖 文件,多个的话用逗号隔开,如果依赖文件没有更改,则不会执行该任务。
缩进为1的行表示任务具体执行的shell语句了,.PHONY修饰的目标表示不管依赖文件 有没有更改,都执行该任务。
执行对应的任务的话,就是在终端上输入 make 目标名
,如 make lint
表示源码检查, make clean
表示清理文件,如果只输入make,则执行第一个目标,对于上面的文件就 是生成helloworld.o了。
现在修改完源码,值需要输入一个make回车就行了,Makefile很强大,可以做很多自动化 的任务,甚至测试,部署,生成文档等都可以用Makefile来自动化,有点像前端的 Grunt和Java里的ant,这样就比较好理解了。
静态检查可以帮你提前找出不少潜在问题来,经典的静态检查工具就是lint,具体到 Linux上就是splint了,可以用yum来安装上。
具体使用的话就是 splint helloworld.c
就行了,它会给出检查出来的警告和错误,还 提供了行号,让你能很快速的修复。
值得注意的是该工具不支持c99语法,所以写代码时需要注意一些地方,比如函数里声明 变量要放在函数的开始,不能就近声明,否则splint会报parse error。
静态检查工具最好不要忽略warning,但是有一些警告莫名其妙,我看不懂,所以还是 忽略了一些,在使用中我加上了 -temptrans -mustfreefresh -usedef
这几个参数。
安装CUnit
了解下单元测试的概念: 一次测试(registry)可以分成多个suit,一个suit里可以有多个 test case, 每个suit有个setup和teardown函数,分别在执行suit之前或之后调用。
下面的代码是一个单元测试的架子,这里测试的是库函数strlen,这里面只有一个suit, 就是testSuite1,testSuit1里里有一特test case,就是testcase,testcase里有一个 测试,就是test_string_length。
整体上就是这么一个架子,suit,test case, test都可以往里扩展。
然后Makefile里增加如下代码
再执行make test就可以执行单元测试了,结果大约如下
可以看到testSuite1下面的test_for_lenth通过测试了。 注意一下,安装完新的动态库后记得ldconfig,否则-l cunit可能会报错 如果还是不行就要 /etc/ld.so.conf 看看有没有 /usr/local/lib , cunit默认把库都放这里了。
就上面的单元测试, 如果使用注释掉那行,执行make test时就会产生coredump。如下
但默认coredump不会保存在磁盘上,需要执 ulimit -c unlimited
才可以,然后要 指定一下coredump的路径和格式:
其中%e是可执行文件名,%p是进程id。然后编译这段代码的时候要加上-g的选项,意思 是编译出调试版本的可执行文件,在调试的时候可以看到行号。
在执行./test.o后就会产生一个coredump了,比如是/tmp/core-test.o-16793, 这时候 用gdb去调试该coredump,第一个参数是可执行文件,第二个参数是coredump文件
挂上去后默认会有一些输出,其中有如下
说明程序遇到了段错误,崩溃了,一般段错误都是因为内存访问引起的, 我们想知道 引起错误的调用栈, 输入bt回车,会看到类似如下的显示
这样大概知道是咋回事了,报错在testcase.c的46行上,再往里就是cunit的调用栈了, 我们看不到行号,好像得有那个so的调试信息才可以,目前还不会在gdb里动态挂符号文件 ,所以就先不管了,输入q退出调试器,其它命令用输入help学习下。
就调用了一个CU_register_suites函数,函数本身应该没有错误,可能是传给他从参数 有问题,就是那个suites,该参数构建的代码如下:
是个CU_SuiteInfo的数组,就感觉是构建这个类型没构建对,然后就看他在哪儿定义 的
在/usr/local/include/CUnit/TestDB.h的696行,具体如下
可以看到,该结构有6个成员,但我们定义的时候只有4个成员,没有设置pSetUpFunc和 pTearDownFunc的,所以做如下修改就能修复该问题了。
对了,gdb用yum安装就行了。
好些时候我们要去分析一个程序的性能,比如哪个函数调用了多少次,被谁调用了, 平均每次调用花费多少时间等。这时候要用gprof,gprof是分析profile输出的。 要想执行时输出profile文件编译时要加-pg选项,
执行上面语句后会在当前目录下生成gmon.out文件, 然后用gprof去读取并显示出来, 因为可能显示的比较长,所以可以先重定向到一个文件prof_info.txt里
参数的含义先这么用,具体可以搜,最后查看prof_info.txt里会有需要的信息, 大概 能看懂,具体可以搜。
Original: https://www.cnblogs.com/onlytiancai/p/3847524.html
Author: 蛙蛙王子
Title: 快速学习C语言二: 编译自动化, 静态分析, 单元测试,coredump调试,性能剖析
原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/536371/
转载文章受原作者版权保护。转载请注明原作者出处!