学过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__
#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)
注释转化就完成了,不过转换之后比原来的内容多了几个换行。