这篇博客,我将整理关于注释转换的知识,首先,得知道,注释转换包括,c语言注释转
换成c++注释,和c++注释转换成c语言注释。
c语言注释的风格:/*这是c语言注释*/
c++语言注释风格://这是c++注释风格
下面,我主要分析将所有的注释转换成c++注释,即就是c语言注释转换成c++注释。
这样的转换会存在以下多种情况:
1.一般情况:/* int i = 0;*/转换后就是//int i = 0;
2.换行问题:
/* int i = 0; */int j = 0;
/* int i = 0; */
int j = 0;
3.匹配问题:
/*int i = 0;/*xxxxx*/转换后就是//int i = 0;/*xxxxx
4.多行注释问题:
/*
int i=0;
int j = 0;
int k = 0;
*/int k = 0;
转换后就是:
//
//int i = 0;
//int j = 0;
//int k = 0;
//
int k = 0;
5.连续注释问题:/**//**/
转换后就是://
//
6.连续的**/问题:
/***/
转换后就是://*
7.C++注释问题:
// /*xxxxxxxxxxxx*/
转换后还是// /*xxxxxxxxxxxx*/
8.字符串里的注释:
"/*helloyaoyao*/"
转换后还是:"/*helloyaoyao*/"
由于情况比较大,所以,我们运用一个叫做有限状态机的东西~~
我们主要的工作是将input.c里的内容通过注释转换写进output.c里。
有限状态机:
有限状态机FSM是软件上常用的一种处理⽅法,它把复杂的控制逻辑分解成有限个稳定
状态,在每个状态上进行处理。有限状态机是闭环系统,可以用有限的状态,处理无穷
的事务。
关于c注释到c++注释的状态转换图如下:
c状态是不会到结束状态的。
下边来看源码(便于读者理解,所以代码中写的注释可能比较通俗易懂一点,也不是特
别专业):
//test.c
#define _CRT_SECURE_NO_WARNINGS 1
#include"commentconvert.h"
int main()
{
FILE *pfRead = NULL;
FILE *pfWrite = NULL;
printf("注释开始\n");
pfRead = fopen(INPUTNAME, "r");
if (NULL == pfRead)
{
perror("open file for read");
exit(EXIT_FAILURE);
}
pfWrite = fopen(OUTPUTNAME, "w");
if (NULL == pfWrite)
{
fclose(pfRead);
perror("open file for write");
exit(EXIT_FAILURE);
}
commentcovert(pfRead, pfWrite);
printf("注释结束\n");
system("pause");
return 0;
}
//commentconvert.h
#ifndef __COMMENTCOVERT_H__
#define __COMMENTCOVERT_H__
#define INPUTNAME "input.c"
#define OUTPUTNAME "output.c"
#include
#include
enum STATE
{
NUL_STATE,
C_STATE,
CPP_STATE,
END_STATE,
STR_STATE
};
void commentcovert(FILE *pfRead, FILE *pfWrite);
void Do_NUL_STATE(FILE *pfRead, FILE *pfWrite);
void Do_C_STATE(FILE *pfRead, FILE *pfWrite);
void Do_CPP_STATE(FILE *pfRead, FILE *pfWrite);
void Do_STR_STATE(FILE *pfRead, FILE *pfWrite);
#endif//
//commentconvert.c
#include"commentconvert.h"
enum STATE state = NUL_STATE;
void commentcovert(FILE *pfRead, FILE *pfWrite)
{
while (state != END_STATE)
{
switch(state)
{
case NUL_STATE:
Do_NUL_STATE(pfRead, pfWrite);
break;
case C_STATE:
Do_C_STATE(pfRead, pfWrite);
break;
case CPP_STATE:
Do_CPP_STATE(pfRead, pfWrite);
break;
case STR_STATE:
Do_STR_STATE(pfRead, pfWrite);
break;
case END_STATE:
break;
}
}
}
void Do_NUL_STATE(FILE *pfRead, FILE *pfWrite)
{
int first = 0;
int second = 0;
first = fgetc(pfRead);
switch (first)
{
case '/':
second = fgetc(pfRead);
if (second == '/')
{
fputc('/', pfWrite);
fputc('/', pfWrite);
state = CPP_STATE; //在无状态下遇到//直接将//写进去,并进入cpp状态
}
else if (second == '*')
{
fputc(first, pfWrite);
fputc('/', pfWrite);
state = C_STATE;//在无状态下遇到/*要将/*变成//写进去,并进入c状态
}
else
{
fputc(first, pfWrite);
fputc(second, pfWrite);//如果遇到其他字符,直接写进去,状态不改变。
}
break;
case EOF:
state = END_STATE;//如果遇到EOF,进入结束状态
break;
case '"':
fputc(first, pfWrite);
state = STR_STATE;//如果遇到",进入字符串状态
break;
default:
fputc(first, pfWrite);//其他情况的字符,直接写进去就行
break;
}
}
void Do_STR_STATE(FILE *pfRead,FILE *pfWrite)
{
int first = 0;
first = fgetc(pfRead);
switch (first)
{
case '"':
fputc(first, pfWrite);
state = NUL_STATE;//在字符串状态如果遇到后引号,将后引号写入,并进入无状态
break;
default:
fputc(first, pfWrite);//其他情况的字符,直接写进去就行
break;
}
}
void Do_C_STATE(FILE *pfRead, FILE *pfWrite)
{
int first = 0;
int second = 0;
int third = 0;
first = fgetc(pfRead);
switch (first)
{
case '*':
second = fgetc(pfRead);
if (second == '/') // 遇到*/ 说明c的注释结束,切换到无状态
{
state = NUL_STATE;
third = fgetc(pfRead);
if (third != '\n')
{
fputc('\n', pfWrite); //如果/后边的字符不是回车,需要写进去回车,然后再把独到的字符放回
ungetc(third, pfRead);
}
else
{
ungetc(third, pfRead);//如果是回车,把回车放回
}
}
else
{
fputc(first, pfWrite);
//如果遇到*,但是后边不是/,把*放进去,*后边的字符放回,比如,/***/,进入c状态以后,
//遇到*,后边的字符也是*,如果把两个*都写进去,后边就只剩下/,就不能找到c状态结束的标志,
//所以,需要把第二个字符原样写回
/*fputc(second, pfWrite);*/
ungetc(second,pfRead); //放回
}
break;
case '\n':
fputc(first, pfWrite);//如果需要回车,吧回车写入,在写入//,状态不变。
fputc('/', pfWrite);
fputc('/', pfWrite);
break;
default:
fputc(first, pfWrite);
break;
}
}
void Do_CPP_STATE(FILE *pfRead, FILE *pfWrite)
{
int first = 0;
int second = 0;
first = fgetc(pfRead);
switch (first)
{
case '\n':
fputc(first,pfWrite);//cpp状态,如果遇到回车,cpp状态结束,进入无状态
state = NUL_STATE;
break;
default:
if (first == EOF)
{
state = END_STATE;
}
else
{
fputc(first, pfWrite);
}
break;
}
}
加入代码之后,竟然发现好丑~~~希望理解。
代码的测试用例:
下边我来谈一下关于写代码时的一些失误:
1.写代码之前,没有将思路整理好,导致出错了也不知道从哪开始调试,排查。
2.对有限状态转移的不理解:比如c状态下没有遇到*/,遇到了其他一般字符,仍然需要
停留在c状态;还有,状态被改变之后,不用人为地调用commentconvert函数,因为进
入当前状态是从commentconvert函数进入的,所以结束当前状态后也会回到commentconvert函数,while循环帮我们实现了。也是因为多余。。
3.state是一个全局变量,软件工程课学到,尽量不要使用全局变量,是因为它不安全,
想改就能改,根据他的这个特性,我们可以做到状态转换。但是,定义全局变量,你也
不要得寸进尺----将全局变量定义在头文件中,这样全局变量在每个文件中都可以被使
用,被改变,而我们只要在我们当前的文件中使用。如果一个工程不是一个人完成,那
么其他人的不留意也会改变它,所以,这样就不好了。(反正意思就是这个了)
4.打开文件就关闭文件,如果读取打开失败,关闭文件再报告错误;如果程序顺利执行
之后,也要关闭文件,粗心的我并没有关闭,以下这两句代码:
fclose(pfRead);
fclose(pfWrite);
应该添加在测试文件的
commentconvert函数调用之后。
这是我在写这个小项目过程中遇到的问题,希望读者会注意~~当然,还有谁会像我这么
笨,犯这样的错误~~