学过C语言的都知道,在C语言中注释是用/*和*/表示的,/*与*/之间的内容就是注释内容。当然用//也可以作为注释,//后面的内容就是注释的内容,不过这种注释通常用于C++之中,今天就用C语言来写个小程序,是关于C语言中的注释转换,如何将C语言中的注释风格转化为C++中的注释风格。
用图来表示就是:(将input.c中的内容通过注释转化写入到Output.c中)
即将/*???*/转化为//,虽然看上去只是一个简单的替换,但是其中还是包含有很多的内容的。换句话说,这样一个小项目还是有几个需要注意的地方。
在我看来其中有以下几个需要注意的地方:
1. 一般情况
/* int i = 0; */
2. 换行问题
/* int i = 0; */int j = 0;
/* int i = 0; */
int j = 0;
3. 匹配问题
/* int i = 0; /*xxxxxxxx*/
4. 多行注释问题
/*
int i = 0;
int j = 0;
int k = 0;
*/int k = 0;
5. 连续注释问题
/**//**/
6. 连续的**/问题
/***/
7. C++注释问题
/*xxxxxxxxxxxxxxxxxxxx*/
这么多种情况我们如何去表示所有情况呢?如果用if--else语句是不是过于麻烦了呢?于是我们可以采用以下的思路,就是列出四种状态,分别是1--空状态(没有状态,就是普通的有效的代码),2--C语言注释状态(遇到/*进入C语言的注释状态),3--C++注释状态(即遇到//后面这一行的都属于C++注释状态),4--结束状态(遇到文件结束标志EOF后产生的状态),这些状态之间遇到特定的条件都可以发生注释转化。
我们可以用图来更形象的表示:
NULL--普通状态 C语言--C语言注释状态 Cpp--C++的注释状态 end--遇到EOF结束了
(注:特殊条件下C语言到普通状态也可以用/n来达到,可以不讨论这种情况)
下面是代码:
首先是头文件:Comment_Convert.h
#ifndef __COMMENT_CONVERT_H__
#define __COMMENT_CONVERT_H__
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
typedef enum Convert_State //用枚举定义四种状态
{
NULL_STATE,
C_STATE,
CPP_STATE,
END_STATE
}Now_State;
#define FILEINPUTNAME "Input.c" //从Input.c之中去读我们的内容
#define FILEOUTOUTNAME "Output.c" //将注释转化好的内容写入Output.c之中
void Comment_Convert();
void Convert_Main(FILE * read, FILE * write);
void Do_NULL_State(FILE * read, FILE * write);
void Do_Cpp_State(FILE * read, FILE * write);
void Do_C_State(FILE * read, FILE * write);
#endif // !__COMMENT_CONVERT_H__
接下来是具体函数的实现:新创建一个源文件 CommentConvert.c,把这些内容写到CommentConvert.c文件中,
#include "CommentConvert.h"
Now_State State;
void Do_C_State(FILE * read, FILE * write) //主要功能是实现在C状态下的读写操作
{
int first = fgetc(read);
int second = 0;
switch (first)
{
case '*':
second = fgetc(read);
if (second == '/') //一般情况,后面的*/直接舍弃
{
int ch = fgetc(read);
if (ch != ' ')
{
fputc('\n', write); //多行注释问题以及连续注释问题解决方法
ungetc(ch, read);
}
State = NULL_STATE;
}
else
{
fputc(first, write); //连续的**/问题
ungetc(second, read);
}
break;
case '/': // 匹配问题解决方法
second = fgetc(read);
if (second == '*')
{
fputc(first, write);
fputc(second, write);
}
else
{
fputc(first, write);
}
break;
case '\n':
fputc(first, write); //换行问题解决方法
fputc('/', write);
fputc('/', write);
break;
case EOF:
fputc(first, write);
State = END_STATE;
break;
default:
fputc(first, write);
break;
}
}
void Do_Cpp_State(FILE * read, FILE * write) //主要功能是实现C++状态下的读写操作
{
int first = 0;
int second = 0;
first = fgetc(read);
switch (first)
{
case '\n': //遇到换行直接改为普通状态即可
fputc('\n', write);
State = NULL_STATE;
break;
case EOF:
fputc(first, write);
State = END_STATE;
break;
default:
fputc(first, write);
break;
}
}
void Do_NULL_State(FILE * read, FILE * write) //主要功能是实现普通状态下的读写操作
{
int first = fgetc(read);
int second = 0;
switch (first)
{
case '/': //普通状态下遇到'/'之后的内容需要分情况
second = fgetc(read);
if (second == '*')
{
fputc(first, write);
fputc('/', write);
State = C_STATE;
}
else if (second == '/')
{
fputc(first, write);
fputc(second, write);
State = CPP_STATE;
}
else
{
fputc(first, write);
fputc(second, write);
}
break;
case EOF:
fputc(first, write);
State = END_STATE;
break;
default:
fputc(first, write);
break;
}
}
void Comment_Convert() //文件的打开以及异常的捕捉
{
FILE * Pread = NULL;
FILE * Pwrite = NULL;
Pread = fopen(FILEINPUTNAME, "r");
if (NULL == Pread)
{
perror("打开文件失败!");
exit(EXIT_FAILURE);
}
Pwrite = fopen(FILEOUTOUTNAME, "w");
if (NULL == Pwrite)
{
fclose(Pread);
perror("打开文件失败!");
exit(EXIT_FAILURE);
}
Convert_Main(Pread, Pwrite);
fclose(Pread);
fclose(Pwrite);
}
void Convert_Main(FILE * read, FILE * write) //转换函数
{
State = NULL_STATE;
while (State != END_STATE)
{
switch (State)
{
case NULL_STATE:
Do_NULL_State(read, write);
break;
case C_STATE:
Do_C_State(read, write);
break;
case CPP_STATE:
Do_Cpp_State(read, write);
default:
break;
}
}
}
接下来就是测试文件:test.c
#include<stdio.h>
void Annotation_Convert() //转化函数
{
Comment_Convert();
}
int main()
{
Annotation_Convert();
return 0;
}
将程序运行起来之后:(测试结果如下:)
要读的文件(Input.c)
输出的文件内容:(Output.c)
注释转化就完成了,不过转换之后比原来的内容多了几个换行。