在我们的C/C++的项⽬目当中会有C、C++两种注释⻛风格,有时为了方便,会将注释全部转为同一种,我这里做的是将c语言风格注释转为c++注释;
c注释为:/int i=1;/
c++注释为://int i=1;
因为在注释转换中有很多情况需要考虑周全,所以可通过下图的梳理来一步步实现代码
接下来就是代码部分,首先是头文件“convert.h”
#ifndef __CONVERT_H__
#define __CONVERT_H__
#include<stdio.h>
#include<stdlib.h>
enum { NULSTAT, CSTAT, CPPSTAT, EOFSTAT };//分别定义四种状态:无注释状态,c注释,c++注释,文件结束状态
#define INPUT "input.c"//定义输入文件
#define OUTPUT "output.c"//定义输出文件
static void convert_work(FILE *ipf, FILE *opf);//定义两个指针分别指向文件内容
void do_null_stat(FILE*ipf, FILE*opf);//无注释状态
void do_cpp_stat(FILE*ipf, FILE*opf);//c++状态
void do_c_stat(FILE *ipf, FILE *opf);//c状态
void convert_main();//测试函数
#endif __CONVERT_H__
源文件”convert.c”:
#define _CRT_SECURE_NO_WARNINGS 1
#include"convert.h"
static int status = NULSTAT;
void do_null_stat(FILE*ipf, FILE*opf)//无注释状态
{
int c = fgetc(ipf);//从input.c中取一个字符,进行判断
switch (c)
{
case'/'://进入注释状态
{
int s = fgetc(ipf);//取c的下一个字符,判断
switch (s)
{
case'*': // 表示"/*" ,c语言注释状态,改为c++状态
fputc('/', opf);
fputc('/', opf);
status = CSTAT;
break;
case'/': // 表示"//",c++状态
fputc('/', opf);
fputc('/', opf);
status = CPPSTAT;
break;
default: //表示'/'是字符,输出c、s
fputc(c, opf);
fputc(s, opf);
status = NULSTAT;
break;
}
}break;
case EOF: //遇到文件结束状态,输出字符
fputc(c, opf);
status = EOFSTAT;
default:
fputc(c, opf);
break;
}
}
void do_c_stat(FILE *ipf, FILE *opf)//c注释状态
{
int c = fgetc(ipf);
switch (c)
{
case'*': //c注释状态,判断下一个字符
{
int s = fgetc(ipf);
switch (s)
{
case'/': //c语言注释状态结束,判断后面的字符是不是换行符
{
int r = fgetc(ipf);//再取一个字符
if (r == '\n')
{
fputc(r, opf);//是换行符则输出字符
}
else
fputc('\n', opf);//不是,则添加一个换行符,并将r字符退回去
ungetc(r, ipf);// ungetc功能是把一个或多个字符退回输入流中,不能是输出流
status = NULSTAT;
break;
default:
fputc(c, opf);
ungetc(s, ipf);
break;
}
}
}break;
case'\n':// 换行之后加上 // ,因为c++只能注释一行
fputc(c, opf);
fputc('/', opf);
fputc('/', opf);
break;
default:
fputc(c, opf);
break;
}
}
void do_cpp_stat(FILE*ipf, FILE*opf) //c++注释状态
{
int c = fgetc(ipf);
switch (c)
{
case'\n': //表示一行注释结束,输出字符,到无注释状态
fputc(c, opf);
status = NULSTAT;
default:
fputc(c, opf);
break;
}
}
static void convert_work(FILE *ipf, FILE *opf)//工作状态,根据不同情况进行选择
{
while (status != EOFSTAT)
{
switch (status)
{
case NULSTAT:
do_null_stat(ipf, opf);
break;
case CPPSTAT:
do_cpp_stat(ipf, opf);
break;
case CSTAT:
do_c_stat(ipf, opf);
break;
default:
printf("ERROR!!!");
break;
}
}
}
void convert_main()//写入输入文件,并判断是否为空
{
FILE *ipf = NULL;
FILE *opf = NULL;
ipf = fopen("input.c", "r");//打开读取文件
if (ipf == NULL)//若文件为空
{
perror("input file open: ");//读取文件失败
exit(EXIT_FAILURE); //EXIT_FAILURE是"stdlib.h"头文件中定义的一个符号常量,表示执行一个程序失败,EXIT_SUCCESS表示执行一个程序成功;二者均可作为exit()的参数使用
}
opf = fopen("output.c", "w");//打开输出文件
if (opf == NULL)
{
perror("output file open: ");
fclose(ipf);
exit(EXIT_FAILURE);
}
convert_work(ipf, opf);
fprintf(opf, "%s\n");
printf("转换成功\n");
fclose(ipf);//关闭两个文件
fclose(opf);
}
主函数main()
#define _CRT_SECURE_NO_WARNINGS 1
#include"convert.h"
int main()
{
convert_main();
return 0;
}
以上就是我所实现的代码程序,接下来可写入输入文件input.c
// 1. 一般情况
int num = 0;
/* int i = 0; */
// 2. 换行问题
/* int i = 0; */int j = 0;
/* int i = 0; */
int m = 0;
// 3. 匹配问题
/*int i = 0;/*xxxxx*/
// 4. 多⾏注释问题
/* int i=0;
int j = 0;
int k = 0; */int k = 0;
// 5. 连续注释问题
//int a = 0;
//int b = 0;
// 6. 连续的 **/ 问题
//*
// 7.C++ 注释问题
// /*xxxxxxxxxxxx*/
接下来就是执行程序,成功后可在文件资源管理器中查看输出文件”output.c”,看输出结果是否符合预期,下面是我的输出文件:
// 1. 一般情况
int num = 0;
// int i = 0;
// 2. 换行问题
// int i = 0;
int j = 0;
// int i = 0;
int m = 0;
// 3. 匹配问题
//int i = 0;/*xxxxx
// 4. 多⾏注释问题
// int i=0;
//int j = 0;
//int k = 0;
int k = 0;
// 5. 连续注释问题
//int a = 0;
//int b = 0;
// 6. 连续的 **/ 问题
//*
// 7.C++ 注释问题
// /*xxxxxxxxxxxx*/
可见是符合转换要求的。
在写程序的过程中最需要注意的是细节!细节!细节!细节!细节!…………
重要的事说上不止三遍