【C语言】C/C++注释转换


前言

编写代码时会有多种注释方式,但有的编辑环境不识别其他的注释方式,因此做个小项目来实现将注释方式统一的改为一种。本次注释转换这个小项目就是将所有的C注释全部转换为C++注释。

概述

要实现这个转换就要先理清实际过程中代码都有哪几种状态!所以先来列一个状态转换机来梳理一下什么情况是什么状态。

简单考虑有以下几种状态:

  • 无状态:代码的正文部分
  • C状态:注释方式为C注释
  • C++状态:注释方式为C++注释
  • END:结束状态

对于此状态我们可以定义枚举常量:

enum STATUS
{
    NUL_STATUS, //无注释状态
    C_STATUS,   //C语言注释状态
    CPP_STATUS, //c++注释状态
    END_STATUS, //结束注释状态
    STR_STATUS  //字符串注释状态
};

* 为了更加清楚直观的了解他们之间的转换关系,用图示的方法来说明一下:*

图片加载

在此来说一下转换机制:先创建一个状态机,在读取到文件时将初始状态先设为NUL_STATUS,然后通过函数从文件中按一个字符一个字符的方式来读取,当读到’/‘时,说明接下来读到的是C_STATUS状态,然后将状态机的状态改为C_STATUS状态,进入C状态后,接下来就是要判断是否读到’/’,如果读到就将状态机设置为 NUL_STATUS状态。当然在进去C状态后还要考虑其他很多情况,具体在代码中来看。当读到’//’时,则进入CPP_STATUS状态,这时将状态机设置为CPP_STAUSE状态,CPP注释是按照行来注释的,所以判断CPP状态结束的标志自然就是’\n’了。在了解了状态机的转换机制之后,接下来就分析需求:

我们要新建并打开input.c文件,对这个文件内部的文件进行读取,然后处理,否则直接提示用户有错误。 接下来,我们还要打开output.c文件,对处理以后的代码进行写入。

图片加载

功能描述:

编写一个小项目将一个一个文件中的注释都转换成C++的注释风格

设计部分:

扫描二维码关注公众号,回复: 2822360 查看本文章
  • 头文件模块:包括模块中需要引用的头文件定义,需要实现的主要函数的声明
  • 头文件中主要函数模块的实现:各个函数部分实现的细节
  • 测试函数:检验函数模块的功能
  • 写入一个输入文件
  • 运行结果记入一个输出文件中

项目展示:

图片加载

参考代码:

CommentConvert.h

/***********************************************************
*                      程序名称:C/C++注释准换               *
*                      编译环境:VS2013                     *
*                      编制日期:2018.6.03                  *
*                                      -----by Hunter      *
***********************************************************/

#ifndef  __COMMENTCONVERT_H__
#define  __COMMENTCONVERT_H__

#include <stdio.h>
#include <stdlib.h>

enum STATUS
{
    NUL_STATUS, //无注释状态
    C_STATUS,   //C语言注释状态
    CPP_STATUS, //c++注释状态
    END_STATUS, //结束注释状态
    STR_STATUS  //字符串注释状态
};


void CommentConvert(FILE* pfIn, FILE* pfOut);
void DoNulStatus(FILE* pfIn, FILE* pfOut);   //无注释状态

void DoCStatus(FILE* pfIn, FILE* pfOut);      //C语言注释状态
void DoCppStatus(FILE* pfIn, FILE* pfOut );   //c++注释状态
void DoStrStatus(FILE* pfIn, FILE* pfOut);     //字符串注释状态


#endif  //__COMMENTCONVERT_H__

CommentConvert.c

#include "CommentConvert.h"

enum STATUS status = NUL_STATUS;

void CommentConvert(FILE *pfIn, FILE *pfOut)
{
    while (status != END_STATUS)
    {
        switch (status)
        {
        case NUL_STATUS:
            DoNulStatus(pfIn, pfOut);
            break;
        case C_STATUS:
            DoCStatus(pfIn, pfOut);
            break;
        case CPP_STATUS:
            DoCppStatus(pfIn, pfOut);
            break;
        case STR_STATUS:
            DoStrStatus(pfIn, pfOut);
            break;
        case END_STATUS:
            break;
        }
    }
}

//无注释状态
void DoNulStatus(FILE *pfIn, FILE *pfOut)
{
    int first = 0;
    int second = 0;
    first = fgetc(pfIn);
    switch (first)
    {
    case '/':
        second = fgetc(pfIn);
        if (second == '/')
        {
            fputc('/', pfOut);
            fputc('/', pfOut);
            status = CPP_STATUS;   //在无状态下遇到//直接将//写进去,并进入cpp状态  
        }
        else if (second == '*')
        {
            fputc(first, pfOut);
            fputc('/', pfOut);
            status = C_STATUS;//在无状态下遇到/*要将/*变成//写进去,并进入c状态  
        }
        else
        {
            fputc(first, pfOut);
            fputc(second, pfOut);//如果遇到其他字符,直接写进去,状态不改变。  
        }
        break;
    case EOF:
        status = END_STATUS;//如果遇到EOF,进入结束状态  
        break;
    case '"':
        fputc(first, pfOut);
        status = STR_STATUS;//如果遇到",进入字符串状态  
        break;
    default:
        fputc(first, pfOut);//其他情况的字符,直接写进去就行  
        break;
    }
}
//字符串注释状态
void DoStrStatus(FILE *pfIn, FILE *pfOut)
{
    int first = 0;
    first = fgetc(pfIn);
    switch (first)
    {
    case '"':
        fputc(first, pfOut);
        status = NUL_STATUS;//在字符串状态如果遇到后引号,将后引号写入,并进入无状态  
        break;
    default:
        fputc(first, pfOut);//其他情况的字符,直接写进去就行  
        break;
    }
}
//C语言注释状态
void DoCStatus(FILE *pfIn, FILE *pfOut)
{
    int first = 0;
    int second = 0;
    int third = 0;
    first = fgetc(pfIn);
    switch (first)
    {
    case '*':
        second = fgetc(pfIn);
        if (second == '/')  // 遇到*/ 说明c的注释结束,切换到无状态  
        {
            status = NUL_STATUS;
            third = fgetc(pfIn);
            if (third != '\n')
            {
                fputc('\n', pfOut);    //如果/后边的字符不是回车,需要写进去回车,然后再把独到的字符放回  
                ungetc(third, pfIn);
            }
            else
            {
                ungetc(third, pfIn);//如果是回车,把回车放回  
            }
        }
        else
        {
            fputc(first, pfOut);
            //如果遇到*,但是后边不是/,把*放进去,*后边的字符放回,比如,/***/,进入c状态以后,  
            //遇到*,后边的字符也是*,如果把两个*都写进去,后边就只剩下/,就不能找到c状态结束的标志,  
            //所以,需要把第二个字符原样写回  
            /*fputc(second, pfOut);*/
            ungetc(second, pfIn);    //放回  
        }
        break;
    case '\n':
        fputc(first, pfOut);//如果需要回车,吧回车写入,在写入//,状态不变。  
        fputc('/', pfOut);
        fputc('/', pfOut);
        break;
    default:
        fputc(first, pfOut);
        break;
    }
}
//C++注释状态
void DoCppStatus(FILE *pfIn, FILE *pfOut)
{
    int first = 0;
    int second = 0;
    first = fgetc(pfIn);
    switch (first)
    {
    case '\n':
        fputc(first, pfOut);//cpp状态,如果遇到回车,cpp状态结束,进入无状态  
        status = NUL_STATUS;
        break;
    default:
        if (first == EOF)
        {
            status = END_STATUS;
        }
        else
        {
            fputc(first, pfOut);
        }
        break;
    }
}

test.c

#define _CRT_SECURE_NO_WARNINGS 1

#include "CommentConvert.h"

void test()
{
    FILE* pfIn = NULL;
    FILE* pfOut = NULL;
    pfIn = fopen("input.c","r");
    if (NULL == pfIn)
    {
        perror("the file for read");
        exit(EXIT_FAILURE);
    }
    pfOut = fopen("output.c", "w");
    if (NULL == pfOut)
    {
        perror("the file for write");
        fclose(pfIn);
        exit(EXIT_FAILURE);
    }
    //注释转换
    CommentConvert(pfIn,pfOut);
    fclose(pfIn);
    fclose(pfOut);

}

int main()
{
    test();
    system("pause");
    return 0;
}

结语

  • status是一个全局变量,曾学到,尽量不要使用全局变量,是因为它不安全,想改就能改,根据它的这个特性,我们可以做到状态转换。但是,定义全局变量,也不要得寸进尺(将全局变量定义在头文件中),这样全局变量在每个文件中都可以被使用,被改变,而我们只要在我们当前的文件中使用。
  • 打开文件就关闭文件:如果读取打开失败,报告错误再关闭文件;如果程序顺利执行之后,也要关闭文件。

好好学习,天天编程

猜你喜欢

转载自blog.csdn.net/qq_41035588/article/details/80561574