C的注释是以字符 /* 开始,以字符 */ 结束,注释被包含的内容。C++的注释是以字符 // 开始,碰到换行符 \n 时结束,注释一行。所以,从C注释转到C++,就是在碰到 /* 时将换成 // ,碰到 */ 时 将其删除。当然,这里会有许多种需要细心情况,我们下面再谈。
完成这个项目,我们需要把代码划分4个状态,NULL(无状态),C状态,CPP状态,END状态。没有接触过这个项目的同学对这四个状态可能不太懂,请耐心往下看。
请阅读下面的状态转换图,首先,我们默认代码开始时是NULL 状态。
①当在NULL状态下碰到 /* 时 进入 C状态(同时将 /* 改为 //);
②在C状态下碰到*/,说明C注释已经结束,此时转回到NULL状态(将*/ 删除),进行下一轮新的判断;
③在NULL状态下碰到 // 时,说明c++注释开始,转到CPP状态;
④当在CPP状态下读到 \n 时,说明C++注释结束,此时转回NULL状态,进行下一轮判断;
⑤⑥⑦:当代码读到EOF时,说明代码已经结束,这时转到END状态,结束程序;
上面状态转换图以及序号讲解只说明了状态之间的转换关系,下面我们列举一下将会碰到哪些情况:
// 1.一般情况
/* int i = 0; */
// 2.换行问题
/* int i = 0; */int j = 0;
/* int i = 0; */
int j = 0;
我们需要将 int j = 0; 换到下一行,保证有效内容不被注释。
// 3.匹配问题
/*int i = 0;/*xxxxx*/
/* 该与那个*/匹配?
// 4.多行注释问题
/*
int i=0;
int j = 0;
int k = 0;
*/int k = 0;
如何将每行都转换成C++注释?
// 5.连续注释问题
/**//**/
连续的C注释怎么处理?
// 6.连续的**/问题
/****/
连续的***/又该怎么处理?
// 7.C++注释问题
// /*xxxxxxxxxxxx*/
C++注释中遇到C注释该怎么办?
这个小项目中我只处理了这几种问题,当然还有许多情况需要同学们去发掘。例如:当一个双引号中包含 /**/ 或者 // 又改怎么解决?
既然我们这个项目是对代码进行操作,那么我们的输入输出必须是函数啦。在相同的目录下建立一个 input.c 作为输入。函数执行完毕后,自动生成输出.c文件。
在这里,我声明一下,下面的代码中用到了fputc函数,fgetc函数,流等C语言知识点。不懂得同学自行查阅资料。
接下来我们来看代码。我用的编译软件是VS2010,写这个项目的时候将其分成了三部分。如图:
Commentconvert.h 是头文件,里面包含了所需的一些宏,枚举类型和操作函数的接口。
#ifndef __COMMENT_CONVERT_H__ //防止头文件重定义错误出现
#define __COMMENT_CONVERT_H__
#include<stdio.h>
#include<stdlib.h>
#define INPUTFILENAME "input.c"//将文件名定义成宏,方便以后的修改
#define OUTPUTFILENAME "output.c"
enum STATE//枚举类型
{
NUL_STATE,
C_STATE,
CPP_STATE,
END_STATE
};
void Commentconvert(FILE *pread,FILE *pwrite);//总操作函数
void DO_NUL_state(FILE *pread,FILE *pwrite);//NULL状态操作函数
void DO_C_state(FILE *pread,FILE *pwrite);//C状态操作函数
void DO_CPP_state(FILE *pread,FILE *pwrite);//CPP状态操作函数
#endif // __COMMENT_CONVERT_H__
Commentconvert.c中放的是操作函数的代码,与主函数分开是为了便于调试。
#include"Commentconvert.h"
enum STATE state=NUL_STATE;
void DO_NUL_state(FILE *pread,FILE *pwrite)
{
int first = 0;
char second = 0;
first = fgetc(pread);
switch(first)
{
case '/':
<span> </span> second = fgetc(pread);
<span> </span> if(second=='*') //NULL状态下 读到 /* 转换到 C状态
<span> </span> {
<span> </span> fputc('/',pwrite); // 放入//
<span> </span>fputc('/',pwrite);
<span> </span>state = C_STATE;
<span> </span> }
<span> </span> else if(second=='/') //NULL状态下 读到 /* 转换到 C++状态
<span> </span> {
<span> </span> fputc(first,pwrite);
<span> </span> fputc(second,pwrite);
<span> </span> state = CPP_STATE;
<span> </span> }
<span> </span> else
<span> </span> {
<span> </span> fputc(first,pwrite);
<span> </span> fputc(second,pwrite);
<span> </span> }
<span> </span> break;
case EOF: //NULL状态下 读到 EOF 转换到 END状态
<span> </span> fputc(first,pwrite);
<span> </span> state = END_STATE;
<span> </span> break;
default:
<span> </span> fputc(first,pwrite);
<span> </span> break;
}
}
void DO_C_state(FILE *pread,FILE *pwrite)
{
char first = 0;
char second = 0;
first = fgetc(pread);
switch(first)
{
case '*':
<span> </span> second = fgetc(pread);
<span> </span> if(second == '/') //换行问题 当读到 */ 时,我们还得判断它的下一个字符是不是\n ,
<span> </span> {
<span> </span> int third = 0;
<span> </span> third = fgetc(pread);
<span> </span> if(third == '\n') //如果是则将\n读到pwrite中,
<span> </span> {
<span> </span> fputc(third,pwrite);
<span> </span> state = NUL_STATE;
<span> </span> }
<span> </span> else //如果不是,我们则添加一个换行符
<span> </span> {
<span> </span>fputc('\n',pwrite);
<span> </span>ungetc(third,pread);
<span> </span>state = NUL_STATE;
<span> </span> }
<span> </span>
<span> </span> }
<span> </span> else // 多个**/问题 如果 * 的下一个字符不是 / ,则将这个字符返还给pread
<span> </span> {
<span> </span> fputc(first,pwrite);
<span> </span> ungetc(second,pread);<span> </span>
<span> </span> }
<span> </span> break;
case '\n': //多行注释问题 C状态下读到\n 放回\n 读到下一行开头 并放入 //
<span> </span> fputc(first,pwrite);
<span> </span> fputc('/',pwrite);
<span> </span> fputc('/',pwrite);
<span> </span> break;
case EOF: // C状态下读到EOF 换到END 状态
<span> </span> fputc(first,pwrite);
<span> </span> state = END_STATE;
<span> </span> break;
default:
<span> </span> fputc(first,pwrite);
<span> </span> break;
}
}
void DO_CPP_state(FILE *pread,FILE *pwrite)
{
char first = 0;
char second = 0;
first = fgetc(pread);
switch(first)
{
case '/':
<span> </span> second = fgetc(pread);
<span> </span> if(second == '*') //C++状态下遇到 /* 不做操作 并放回
<span> </span> {
<span> </span> fputc(first,pwrite);
<span> </span> fputc(second,pwrite);
<span> </span> }
<span> </span> else
<span> </span> {
<span> </span> fputc(first,pwrite);
<span> </span> fputc(second,pwrite);
<span> </span> }
<span> </span> break;
case EOF: //c++状态下遇到 EOF 转换到END
<span> </span> fputc(first,pwrite);
<span> </span> state = END_STATE;
<span> </span> break;
case '\n': //c++状态下遇到 \n ,转换到NULL状态
<span> </span> state = NUL_STATE;
default:
<span> </span> fputc(first,pwrite);
<span> </span> break;
}
}
void Commentconvert(FILE *pread,FILE *pwrite)
{
while(state!=END_STATE)
{
switch(state)
<span> </span>{
<span> </span>case NUL_STATE:
<span> </span>DO_NUL_state(pread,pwrite);
<span> </span>break;
<span> </span>case C_STATE:
<span> </span>DO_C_state(pread,pwrite);
<span> </span>break;
<span> </span>case CPP_STATE:
<span> </span>DO_CPP_state(pread,pwrite);
<span> </span>break;
<span> </span>case END_STATE:
<span> </span>break;
<span> </span>}
}
}
test.c中放的是调试代码,包括主函数。
#include"Commentconvert.h"
int main()
{
FILE *pread=NULL;
FILE *pwrite=NULL;
printf("转换开始");
pread=fopen(INPUTFILENAME,"r");
if(NULL==pread)
{
printf(" open file for read");
exit(EXIT_FAILURE);
}
pwrite=fopen(OUTPUTFILENAME,"w");
if(NULL==pwrite)
{
fclose(pread);
printf(" open file for write");
exit(EXIT_FAILURE);
}
Commentconvert(pread,pwrite);
printf("转换结束");
fclose(pread); //用完之后,要关闭它。(良好编程习惯)
fclose(pwrite);
return 0;
}
如果你的代码成功的话,将上面列举的问题输入 input.c,执行代码,你会看到下面的结果。
套用我学长的一句话,为什么选择当程序员,“工资高,自由度大,前景好,有车有房有未来”。 哈哈, 同志们加油!