版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、摘 要本课题的主要任务是开发一款代码行数统计器,专门用于统计C语言或C+语言程序代码文件。该统计器的主要功能是统计代码文件的文件行数、有效代码行数、注释行数、空白行数,以及计算代码的注释率。和那些只能统计单个文件的统计器不同,这款统计器能够接受文件夹路径,批量统计整个文件夹的所有文件,包括子文件夹中的有效文件。这样可以大大的提高统计效率,节约用户的时间,使编程人员能集中更多精力编写程序。该统计器在测试时统计了大量的文件,基本上没有错误,精度相当高,用户可安全使用。本课题所用的编译环境是C-free 5,最终结果exe可执行文件。目 录第1章 绪论1第2章 需求分析22.1可行性分析22.2整体
2、功能2第3章 关键技术33.1文件操作33.1.1文件的打开与读取33.1.2遍历文件夹33.2变量处理43.3错误识别与防范43.3.1内存错误43.3.2用户输入有误4第4章 概要设计54.1.1路径判断54.1.2遍历文件64.1.3字符判断74.1.4信息统计输出8第5章 详细设计105.1文件类型判断105.2遍历文件夹105.3文件字符的判断和变量处理115.3.1定义变量115.3.2注释标记125.3.3Space和tab125.3.4转义字符125.3.5其他字符13第6章 设计结果和使用说明146.1程序运行界面146.2使用说明15第7章 总结16致谢18参考文献19附录
3、A201第1章 绪论随着计算机技术的发展与普及,越来越多的人开始学习编程技术。而C语言是在国内外广泛使用的一种计算机语言,它凭借自己功能丰富、使用灵活、可移植性强等优点,不仅为计算机专业工作者所使用,还博得了广大计算机应用人员以及计算机爱好者的青睐。但在项目开发的时候,项目负责人经常需要审查代码、统计各种相关信息(如:代码总行数、注释行数、注释率等),其中项目的源代码行数和注释率是非常重要的项目健康度指标,一般来说,比较理想的注释率在20%30%,这样的代码比较容易维护。因此,为了减少编程人员的工作量,提高工作效率,就需要设计一种专门的软件来替代项目开发人员统计代码行数以及注释行数等相关信息。
4、这款C语言代码统计器能够接收用户输入的文件夹路径,批量统计整个文件夹的所有文件,更大程度地提高了项目开发人员的工作效率。第2章 需求分析2.1 可行性分析前面已经说过,现在使用计算机编程的人已经越来越多了,其中使用C语言或C+语言编程的更是占了很大的比列。由于C语言的编写工程很大,但有时却需要统计一些其中的有关信息。如果用人工统计的话,既浪费时间,也浪费编程人员的精力,降低工作效率。所以现在对一些辅助型的软件需求量特别大。面对这样的现状,这款C&C+代码统计器应运而生。它能够弥补人力的不足,大大地提高了人们的工作效率,使程序员能集中精力编写更多有用的程序。另一方面,这个代码统计器占用空
5、间很小,电脑的要求很低并且很便携,更能使大多数人接受,而且使用简单,更便于推广。总体来说,这款代码统计器满足了当前大多数编程人员的部分需求,并且凭借着它独自的特点使大多数人能够接受。2.2 整体功能这款C&C+代码统计器是用纯C编写的控制台程序,它既能单独地够统计单个文件,还能批量统计整个文件夹中所有文件,这也是前面说的提高效率的关键地方。主要统计的项目有:文件总数、代码总行数、有效代码总行数、注释行数、空白行数以及注释率等,由此看出,该统计器不仅可以用在它的本职工作(统计代码行数),还能用来统计一个文件夹中的所有文件个数。除了以上功能,该统计器还有以下优点:操作简单,用户既可以手动输
6、入所需统计的文件或文件夹路径,也可以直接将文件或文件夹拖入特定区域进行统计,方便快捷。由于该代码统计器是在DOS下运行的控制台程序,所以运行速度比Windows程序要快很多,这也弥补了它在界面上的劣势。第3章 关键技术3.1 文件操作前面已经说到,文件操作很重要,特别是文件夹的遍历问题。3.1.1 文件的打开与读取在C标准库函数中,头文件<stdio.h>下包含了各种输入输出函数,其中就包括了实现文件操作的一系列函数:FILE *fopen(char *filename, char *mode) :以指定的方式打开一个文件。在该代码统计器的程序中,是以只读(r)方式打开一个文件的。
7、为什么选只读呢?因为以只读方式打开的文件,无论是否有其他程序在使用它,都不会影响到对它的统计,这样使用起来也是更加的方便。int fgetc(FILE *fp) :从文件中当前位置读一个字符。由于该程序中需要连续读取两个字符,而这个函数在读取时会自动移动文件内部指针,所以必须采取特殊措施才能实现连续读取。该程序是将文件打开两次,两个指针一前一后交替读取字符,从而达到连续读取的目的。int fclose(void) :关闭所有已打开的文件。文件打开之后一定要关闭,否则将会使数据丢失。3.1.2 遍历文件夹 在头文件< io.h>中,定义了一个结构体:struct _finddata_
8、t unsigned attrib; time_t time_create; time_t time_access; time_t time_write; _fsize_t size; char name260;并且定义函数 long _cdecl _findfirst(const char *, struct _finddata_t *),利用该函数,能够对一个文件夹路径进行检索,返回所给文件夹路径的子文件或子文件夹指针。从而,我们就可以从这个返回的结构体指针中获取文件夹子目录的全部相关信息,例如:文件或文件夹名、文件类型、文件大小以及更改日期等得知这些信息之后,我们只需要对不同类型的文件分
9、别进行处理,就能实现对整个目录的遍历。这个程序是采用递归算法,如果所给文件夹的子目录是文件,则直接统计;如果所给文件夹的子目录是文件夹,则将对子文件夹的路径继续调用该函数,直至没有子文件夹为止。3.2 变量处理由于要统计代码源文件中的文件行数、代码函数、注释行数、空白行数等信息,则需要使用多个变量来分别统计各种信息。并且,有些变量不只在一个函数中使用,有些变量在递归时不能改变它的值。为此,在该统计器的程序设计中,一共使用了五个全局变量、九个静态变量。其中,五个全局变量分别统计用户输入的文件夹中的文件总数、总代码行数、总有效代码行数、总注释行数、总空白行数;九个静态变量位于字符判断的模块,分别用
10、来统计单个文件的代码行数、有效代码行数、注释行数、注释率,以及用来标记字符是否在注释中、是否在字符串中、该行是否有注释、是否有代码等。这样做减少了函数之间值的地址的传递,出错也就更少,安全性也就越高。3.3 错误识别与防范3.3.1 内存错误C语言中,指针一直都是最容易出错的地方。为了防止指针出错,本程序在关键处使用了C标准库函数中,<assert.h>头文件下void assert(int exp) 这个函数,它是用于表达式结果的正确性测试并且当表达式结果为假时使程序终止。本程序总共在三个地方使用到了它:1、 在接受用户所输入的文件(夹)路径,将该路径传递给一个数组时,用于判断数
11、组下标是否越界。2、 在递归遍历文件夹时,函数入口参数是一个指针变量,接受文件夹路径。此处是用它来防止指针为空的情况。3、 在判断文件是否为C或C+代码文件时,和第二种情况差不多,也是用来防止接收的文件名指针为空。3.3.2 用户输入有误为了让用户更好地使用软件,就需要有很好的人机对话,当用户输入错误信息的时候,就应该有所提示。这款软件能识别用户所输入的参数是否为文件(夹)路径,并且会给出相应的语言提示。并且,当用户所输入的文件或文件夹路径不存在时,也会给出相应的提示或警告,从而不会出现统计对象出错等现象。第4章 概要设计4.1.1 路径判断为了高效统计用户所需的代码文件,就要求统计器能够批量
12、统计文件夹。因此,首要任务就是要识别用户输入的信息,看用户所给的路径名是文件还是文件夹,从而做出相应的处理,该部分流程图如下:判断完用户所输路径后,就需要对其分开处理。因为该代码统计器是专门用来统计C语言或C+语言的,所以当接收路径名为文件时,就需要判断该文件的种类,如果是C或C+程序代码文件,则直接进行统计;否则报错,提示用户文件格式不正确。该部分流程图如下:4.1.2 遍历文件因为要实现批量处理文件,所以如果用户输入的是文件夹路径,就需要对该文件中的所有文件进行遍历,包括子文件夹中的所有文件,再分别统计出各个文件的相关信息。文件遍历是一个很关键的部分,遍历是否完全关系到统计的精确度,该统计
13、器采用的是递归遍历法,其流程如下:4.1.3 字符判断如果说文件遍历很重要,那么对文件字符的判断则是整个程序的核心部分。因为这部分直接关系到单个文件的统计是否正确。由于代码中存在许多关键字符,如:“/*”,“*/”,“/”等,这都需要两个字符连续判断,所以在读取时,需要从文件中连续读取两个字符。该部分还关系到了文件的打开与读取,以及文件有效性的判断和从文件中读取字符,大致流程如下:字符判断又分为几大类:1、 注释符:“/*”、“*/”、“/”;2、 引号:单引号和双引号;3、 空白:空格和制表符;4、 转义字符:如“”;5、 换行符:回车键;6、 其它一般字符。这些字符的判断以及相应的处理在后
14、面会相对详细的给出说明,这里就不赘述。4.1.4 信息统计输出字符判段以及相应的处理后,就需要对文件行数、有效代码行数、注释率等一系列信息进行统计并输出,然后结束。大致流程如下:这就是该代码统计器的设计思路,至于一些关键部分的处理,接下来会有详细的说明。第5章 详细设计该代码统计器的关键部分有三个:文件类型的判断、文件夹的遍历、文件字符的判断和变量处理。5.1 文件类型判断C和C+源代码文件加起来一共有三类,分别是以.C、.H、.CPP为后缀名,有了这个依据,我们就能准确地从一系列文件中找出我们所需要的这三种文件。在设计程序时,为了避免有些文件对判断的干扰(比如:文件名为 *ctxt 这样的文
15、件),我们是从文件名末尾开始判断的。由于由函数接收来的文件名是正常次序的,因此需要另外设定函数将文件名字符串倒置,然后再依据文件名后缀来进行判断筛选。值得一提的是,文件命名时不区别字母大小写,所以在判断之前要做一下简单的处理,那就是把文件名字符串的字符全部转换成小写或大写,这样就避免了同样的事代码写两遍,显得啰嗦复杂,不简明,使用函数为“stdio.h”头文件下的strlwr( )函数。具体的字符串倒置和判断方法见附录A,代码中的子函数int FileJudge(char const *p)部分。单独将此部分提出来用一个子函数实现的目的是:以后如果增加了对其它语言的程序代码文件的统计,只需在此
16、模块的文件类型的判断语句上增加一种或几种文件类型就行了,而不需要改动整个程序5.2 遍历文件夹前面已经粗略提到过遍历文件夹的方法,这里再做具体的说明。前面讲过在头文件< io.h>中,定义了一个结构体:struct _finddata_tUnsigned attrib; /* Attributes, see constants above. */time_ttime_create;time_ttime_access; /* always midnight local time */time_ttime_write;_fsize_t size;char nameFILENAME_MA
17、X; /* may include spaces. */;并且定义了:int _cdecl _MINGW_NOTHROW _findfirst(const char *, struct _finddata_t *);int _cdecl _MINGW_NOTHROW _findnext (long, struct _finddata_t*);int _cdecl _MINGW_NOTHROW _findclose (long) 这三个函数。利用这三个函数,就能够实现对一个文件夹路径进行检索,并返回所给文件夹路径的子文件或子文件夹指针,并且关闭文件夹。从而,我们就可以从这个返回的结构体指针中获取
18、文件夹子目录的全部相关信息,例如:文件或文件夹名、文件类型、文件大小以及更改日期等。有了这些信息,我们就能准确的对整个文件夹子目录中的各个元素进行判断,也就实现了给定目录下的文件遍历了。具体实现的过程请参阅附录A,代码中子函数int TraverseFile (char const *path)部分。正如代码所示,该代码统计器是采用递归算法来遍历文件夹的,即如果用户输入的文件夹路径下,有子文件夹,则再对该子文件夹调用上述函数,直至某一子文件夹没有子文件夹为止。这段代码中出现的 FileStatistic() 函数,是写代码时自定义的用来对单个文件进行统计的子函数,详细定义请参阅附录A中的相应部
19、分;MAX_PATH 是宏定义的一个常数,用于接收文件夹路径,MAX_PATH的定义的值为1024;另外在文件类型判断处还出现了_A_SUBDIR、_A_ARCH等参数,这是在头文件中已经宏定义好的文件的类型,具体定义如下:#define _A_NORMAL 0x00 /* Normal file - No read/write restrictions */#define _A_RDONLY 0x01 /* Read only file */#define _A_HIDDEN 0x02 /* Hidden file */#define _A_SYSTEM 0x04 /* System fil
20、e */#define _A_SUBDIR 0x10 /* Subdirectory */#define _A_ARCH 0x20 /* Archive file */以上部分就是该代码统计器十分关键的部分,如果不能实现该部分的功能,即就不能实现文件夹的遍历,就不能对文件夹批量处理,程序的速度就不能提高。5.3 文件字符的判断和变量处理这部分是整个项目程序的核心部分,该模块基本上实现了对单个文件的统计,所以内容比较多,这里分开来阐述。5.3.1 定义变量要想统计一个文件的代码行数、注释行数、空白行数、有效代码行数等很多相关信息,必然要用许多变量来分开处理。在该模块程序设计中,一共涉及到了十一个
21、静态变量,它们分别如下:int static iCountNote = 0; /*统计注释行数 */int static iCountCode = 0; /*统计有效代码行数 */int static iCountblank = 0; /*统计空白行数 */int static iCountAll = 0; /*统计代码总行数 */int static iHaveCode = 0; /*判断该行是否有代码 */int static iHaveNote = 0; /*判断该行是否有注释*/ int static iC_or_N2 = 0, iC_or_N = 0; /* 判断字符是否在注释中 *
22、/int static iQuotation_mark1 = 0, iQuotation_mark2 = 0; /*判断字符是否在引号中 */int static i = 1;各个变量的作用在上述代码也有注释,这里不再赘述。有必要说明的是,这里全都定义成了静态变量,这样做的目的是在递归调用该函数时,保持这些变量不改变,其作用相当于全局变量。只不过和全局变量相比,它只用于定义它的函数函数本身,不能被其它函数使用,但它更加节约计算机内存空间,也不容易出错,函数可移植性也大大增强了。详细使用见附录A中相应部分。5.3.2 注释标记在C和C+语言程序代码中,一共有两种注释方式:“/*.*/”、“/.”
23、,既然要统计注释行数,则需要对这两种特殊标记作出相应处理,该部分十分关键,它不仅是注释标记,同时也作为代码的标记,如果一个判断错误,就会导致整个结果出错,程序中该部分关键代码如下:else if ('/' = ch && '*' = NextCh && !iQuotation_mark1 && !iQuotation_mark2 && !iC_or_N2 ) if (iHaveNote = 0) i = 0; iC_or_N = 1; iHaveNote = 1; 这里只说明了“/*/”的处理,“/
24、.”同理。其中有两个判断处有iQuotation_mark1、iQuotation_mark2这两个变量的判断,其目的是为了避免出现以下情况:“fhsdjkgdfj /* gdfgf */ gfgdfgdfgsgf / ” 即在字符串中出现注释标记符。另外还有两处出现如下语句:if (iHaveNote = 0) i = 0; 这里设置i这个变量是为了让“/”、“/*”绑定在一起,具体实现方法是在i为0的时候不执行任何语句,这样该函数接收的两个字符就会相当于没接收。这是为了避免“/*/”这样的字符串,有了这个i的判断后,就不会出现统计完“/*”马上统计“*/”的情况,而是跳过“*/”统计下一对
25、字符。5.3.3 Space和tab对于这两个特殊的字符,在程序设计时不对它做任何处理,因为空白既不算注释,也不算代码,它是特殊的存在。5.3.4 转义字符有几个特殊的转义字符:“”、“”、“”,这三个字符它们会互相干扰,比如在字符串中出现“” ,就会导致字符串的边界判断出错,所以把它们单独列出来处理。再比如在引号中如果出现了“/*”字符,就不能算作注释,这些都要特殊考虑特殊处理。大致代码如下:else if ('' = ch && '"' = NextCh && (iQuotation_mark1 | iQuotati
26、on_mark2) /* 排除转义字符"在字符串中的干扰*/ i = 0;else if ('' = ch && '' = NextCh && (iQuotation_mark1 | iQuotation_mark2) /* 排除转义字符在字符串中的干扰*/ i = 0;这里只说了双引号的处理,单引号同样的处理,这里不再赘述。5.3.5 其他字符换行符是统计行数的最终标记,所有的行数统计基本都在这里进行,它只是根据各个参数的数值,再来对统计的数据进行自加。由于换一行之后,所有情况都是未知的,所以在换行符这里还要对各个数据
27、进行初始化。剩余的字符有两种处理:如果当前不在代码中(即iC_or_N = 0 && iC_or_N2 = 0),则这些字符算代码;否则,这些字符算注释。第6章 设计结果和使用说明6.1 程序运行界面开始界面:单个文件统计界面:文件夹统计界面:上图是对文件夹中子文件夹的文件进行统计上图是输出整个文件夹的整体信息6.2 使用说明该统计器由于是控制台程序,所以操作十分简单。用户可以按照提示在指定位置输入需要统计的文件或文件夹路径,然后键入回车键,则程序就会自动运行并输出用户所需信息;用户还可以直接将需要统计的文件或文件夹拖入运行界面中,再键入回车键,即可统计出相关信息。统计并显示的
28、数据分别是:1、 单个文件:代码行数、有效代码行数、注释行数、空白行数、注释率;2、 文件夹:除了该文件夹中所有文件的相关信息外,还统计了文件夹中的文件总数、代码总行数、有效代码总行数、总注释行数、总空白行数、还有总注释率。用户可以根据这些数据来审查自己的代码以及项目的健康度指标(注释率)。 第7章 总结致谢参考文献1 谭浩强著 C程序设计(第三版)清华清华出版社2 美 K.N.King,吕秀锋译 C语言程序设计现代方法人民邮电出版社3 C语言库函数大全附录A/* Function name: CharJudge* Descriptions: 判断文件中的单个字符,并改变相关的变量*/int
29、CharJudge(char ch, char NextCh, int k) int static iCountNote = 0; /* 统计注释行数 */ int static iCountCode = 0; /* 统计有效代码行数 */ int static iCountblank = 0; /* 统计空白行数 */ int static iCountAll = 0; /* 统计代码总行数 */ int static iHaveCode = 0; /* 判断该行是否有代码 */ int static iHaveNote = 0; /* 判断该行是否有注释 */ int static iC_
30、or_N2 = 0, iC_or_N = 0; /* 判断字符是否在注释中 */ int static iQuotation_mark1 = 0, iQuotation_mark2 = 0; int static i = 1; /* * 对各种字符作出判断 ,并改变相关参数 */ if (k = 0) if (i = 0) i = 1; else if (' ' = ch | 9 = ch); /* 对空格和tab符不做任何处理 */ else if ('/' = ch && '*' = NextCh && !iQ
31、uotation_mark1 && !iQuotation_mark2 && !iC_or_N2 ) if (iHaveNote = 0) i = 0; iC_or_N = 1; iHaveNote = 1; else if ('/' = ch && '/' = NextCh && !iQuotation_mark1 && !iQuotation_mark2 && !iC_or_N ) if (iHaveNote = 0) i = 0; iC_or_N2 = 1; i
32、HaveNote = 1; else if (39 = ch && !iQuotation_mark2) if ( !iC_or_N && !iC_or_N2) iQuotation_mark1 = !iQuotation_mark1; else if ('' = ch && '"' = NextCh && (iQuotation_mark1 | iQuotation_mark2) /*排除转义字符"在字符串中的干扰*/ i = 0; else if ('' =
33、ch && 39 = NextCh && (iQuotation_mark1 | iQuotation_mark2) i = 0; else if ('' = ch && '' = NextCh && (iQuotation_mark1 | iQuotation_mark2) /*排除转义字符在字符串中的干扰*/ i = 0; else if ('"' = ch && !iQuotation_mark1) if ( !iC_or_N && !
34、iC_or_N2) iQuotation_mark2 = !iQuotation_mark2; else if ('*' = ch && '/' = NextCh && iC_or_N) iC_or_N = 0; iHaveNote = 1; i = 0; else if ('n' = ch) /* 以回车为标记,进行行数统计 */ if (iHaveNote) /* 如果该行有注释,注释行加一 */ iCountNote+; if (iHaveCode) /* 如果该行有代码,代码行加一 */ iCountCod
35、e+; if (!iHaveCode && !iHaveNote) /* 若该行无注释无代码,空白行加一*/ iCountblank+; iHaveNote = 0; iHaveCode = 0; iC_or_N2 = 0; iCountAll+; else if ( !iC_or_N && !iC_or_N2 ) iHaveCode = 1; else iHaveNote = 1; else if(k = 1) /* 对统计数据的变量进行初始化 */ iCountNote = 0; iCountCode = 0; iCountblank = 0; iCount
36、All = 0; iHaveCode = 0; iHaveNote = 0; iC_or_N2 = 0; iC_or_N = 0; iQuotation_mark1 = 0; iQuotation_mark2 = 0; i = 1; else /* 根据k的值返回所需的变量值 */ switch (k) case 2: return iCountAll; break; case 3: return iCountCode; break; case 4: return iCountNote; break; case 5: return iCountblank; break; case 6: ret
37、urn iHaveNote; break; case 7: return iHaveCode; break; default: break; return 1;/* Function name: FileJudge* Descriptions: 判断待统计的文件是否为C语言代码文件(后缀名为.c或.h.或cpp)*/int FileJudge(char const *p) char str255 = 0; int i = 0; strcpy(str, p); strlwr(str); /* 将文件名字符串转化成小写 */ i = strlen(str) - 1; if ( 'c' = stri && '.' = stri-1 ) return 1; else if ( 'p' = stri && 'p' = stri-1 && 'c' = stri-2 && '.' = stri-3 ) return 1; else if ( 'h' = stri && '.&
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 高中语文专题一辩论第1课原毁课件苏教版选修唐宋八大家散文蚜
- 校园安全教育班会教案
- 四年级公共安全教育教案
- 山东省滕州市2024-2025学年上学期期中复习卷八年级英语试题(无答案)
- 北京远洋LAVIE项目推广思路
- 2013-2016年中国戊唑醇行业市场调研及十二五规划分析研究报告
- 2010-2013年乙二醇行业发展及竞争力分析报告
- 2024至2030年中国天然红纹石手链行业投资前景及策略咨询研究报告
- 2024至2030年中国塑料餐勺数据监测研究报告
- 道路交通安全课件第-七-章-交通环境与交通安全
- 阿尔兹海默症又病
- 中国(教育部)留学服务中心招聘笔试真题2023
- 青海三新农电公司招聘试卷
- 稻田养蟹项目总结汇报
- 勇敢的人先享受世界
- 人教版八年级英语上册完形填空14道(含答案详解)
- 画法几何工程制图课件计算机绘图讲义
- 医疗安全不良事件分析报告
- 西师大版小学6年级(上)第一单元测试卷数学试题(一)含答案与解析
- 华为大学人才培养与发展实践
- 文化旅游安全培训文案标题
评论
0/150
提交评论