0xAA55 发表于 2014-11-17 08:38:57

【C】C语言写的给C语言源代码去掉注释的程序

作用就是去掉注释。别小看这个程序了,因为去掉注释并不像大家想的那么简单——因为//和/*不一定都是注释,比如下面的代码:
char szUrl[]="http://www.0xaa55.com/";
看见没有?这里就不能简单地把“//www.0xaa55.com/";”去掉了。
解决的方法是对"和'进行识别,把引号内的//和/*无视掉,仅对“正常”的//和/*进行判定。这样就能保证不会错误地删除不是注释的部分了。

我写的这个控制台程序用法很简单,它只有一个参数:文件名。然后经过处理的代码直接输出到stdout,如果你要把内容写入文件,请使用重定向命令:cmntkill a.c>a.txt//=============================================================================
//作者:0xAA55
//论坛:http://0xaa55.com
//版权所有(C) 2013-2014 技术宅的结界
//
//用途:
//将C、C艹文件中的注释去掉
//-----------------------------------------------------------------------------
#include<stdio.h>
#include<stdlib.h>
#include<string.h>

//=============================================================================
//函数:Usage
//描述:打印程序的用法。
//-----------------------------------------------------------------------------
void Usage(char*argv0)
{
        fprintf(stderr,
"cmntkill: This tool is used to remove the comments in a C\\C++ source file.\n"
"Usage:\n"
"%s inputfile\n",
        argv0);
}

#define        LineLen        80

//=============================================================================
//函数:ReadLine
//描述:读取完整的一行
//返回分配了内存的一行字符串,pLineLength返回行长度(不包括结尾的0)
//-----------------------------------------------------------------------------
char*ReadLine(FILE*fp,size_t*pLineLength)
{
        char szLineBuf;
        char*pChNewLine;
        size_t cbLineLen=0;
        long pCurPos;
       
        pCurPos=ftell(fp);
        while(!feof(fp))
        {
                //连续读取文件,直到找到换行符
                fread(szLineBuf,1,LineLen,fp);
                pChNewLine=strchr(szLineBuf,'\n');
                if(pChNewLine)//如果找到换行符
                {
                        cbLineLen+=(size_t)pChNewLine+1-(size_t)szLineBuf;//计算行长度

                        //转到读取的位置
                        fseek(fp,pCurPos,SEEK_SET);

                        //分配内存来存放字符串
                        pChNewLine=(char*)malloc(cbLineLen);
                        if(!pChNewLine)
                                return NULL;

                        //读取行
                        fread(pChNewLine,1,cbLineLen,fp);
                        pChNewLine='\0';//去掉结尾的换行符
                        if(pLineLength)//返回行长度
                                *pLineLength=cbLineLen-1;
                        return pChNewLine;
                }
                else
                        cbLineLen+=LineLen;
        }
       
        //如果读到文件尾都没遇到换行符,则这个文件只有一行
        fseek(fp,0,SEEK_END);
        cbLineLen=(size_t)ftell(fp)-(size_t)pCurPos;
        if(!cbLineLen)
        {
                fgetc(fp);//使feof返回非零
                return NULL;
        }

        //转到读取的位置
        fseek(fp,pCurPos,SEEK_SET);

        //分配内存
        pChNewLine=(char*)malloc(cbLineLen+1);
        if(!pChNewLine)
                return NULL;

        //读取行
        fread(pChNewLine,1,cbLineLen,fp);
        pChNewLine='\0';//结尾
        if(pLineLength)//返回行长度
                *pLineLength=cbLineLen;
        return pChNewLine;
}


//=============================================================================
//函数:RightTrim
//描述:把字符串右边的空格、TAB去掉
//-----------------------------------------------------------------------------
void RightTrim(char*szLine)
{
        size_t cbLine;
        char*pChr;

        cbLine=strlen(szLine);
        pChr=&szLine;

        while(cbLine--)
        {
                switch(*pChr)//判断字符
                {
                case' ':
                case'\t':
                        *pChr='\0';//去掉空格或TAB
                        pChr--;
                        continue;
                default://遇到其它字符,则返回
                        return;
                }
        }
}

//=============================================================================
//函数:main
//描述:程序入口点
//-----------------------------------------------------------------------------
int main(int argc,char**argv)
{
        FILE        *fp;
        char        *szLine;
        size_t        cbLine;
        int                InComment=0;//是否在注释内
        size_t        LineNo=1;

        if(argc<2)
        {
                Usage(argc?argv:"defconst");
                return 1;
        }

        fp=fopen(argv,"r");
        if(!fp)
        {
                fputs("Could not read file.\n",stderr);
                return 2;
        }

        while(!feof(fp))
        {

                szLine=ReadLine(fp,&cbLine);
                if(!szLine)
                {
                        if(feof(fp))
                                break;
                        fputs("Insufficient memory.\n",stderr);
                        goto Cleanup;
                }

                RightTrim(szLine);

                //如果是在/**/的注释内
                if(InComment)
                {
                        char*pEnd;//直接找结尾
                        pEnd=strstr(szLine,"*/");
                        if(pEnd)//找到了结尾
                        {
                                InComment=0;//在注释外了
                                pEnd+=2;//看后面有没有内容
                                if(*pEnd)//有的话把后面的内容覆盖到前面
                                {
                                        size_t cbRemains;
                                        cbRemains=strlen(pEnd);
                                        memmove(szLine,pEnd,cbRemains);//覆盖到前面
                                        szLine='\0';
                                        //接着就会跳到if(!InComment)那里继续处理
                                }
                                else//后面没内容,这是空行
                                {
                                        fputc('\n',stdout);//输出一个空行
                                        free(szLine);
                                        continue;
                                }
                        }
                        else//没找到结尾,整行都是注释
                        {
                                fputc('\n',stdout);//输出一个空行
                                free(szLine);
                                continue;
                        }
                }

                //如果是在/**/的注释外
                if(!InComment)
                {
                        char*pStr;

                        //遍历这行字符串
ParseStr:        for(pStr=szLine;*pStr;pStr++)
                        {
                                if(!strncmp(pStr,"//",2))//如果找到了单行注释
                                {
                                        *pStr='\0';//直接将其干掉
                                        break;//这一行处理结束
                                }
                                if(!strncmp(pStr,"/*",2))//如果找到了多行注释
                                {
                                        char*pEnd;//直接找结尾
                                        pEnd=strstr(pStr,"*/");
                                        if(pEnd)//如果找到了说明这个多行注释只在一行内
                                        {
                                                pEnd+=2;//跳过注释结束的标识
                                                if(*pEnd)//后面有内容
                                                {
                                                        size_t cbRemains;
                                                        cbRemains=strlen(pEnd);
                                                        memmove(pStr,pEnd,cbRemains);//覆盖到前面
                                                        pStr='\0';
                                                        pStr--;
                                                        continue;
                                                }
                                                else
                                                {
                                                        *pStr='\0';//直接把/*开始的内容全删
                                                        break;//这一行处理结束
                                                }
                                        }
                                        else
                                        {
                                                *pStr='\0';
                                                InComment=1;
                                                break;
                                        }
                                }

                                if(*pStr=='\\')//如果找到斜杠
                                {
                                        if(!pStr)//并且后面是空,这个斜杠是续行符
                                        {
                                                char*szNextLine;//追加下一行的数据
                                                szNextLine=ReadLine(fp,&cbLine);
                                                if(!szNextLine)
                                                {
                                                        if(feof(fp))
                                                        {
                                                                fprintf(stderr,
                                                                        "%s(%u):unexpected end of file found\n",
                                                                        argv,LineNo);
                                                                goto Cleanup;
                                                        }
                                                        fputs("Insufficient memory.\n",stderr);
                                                        goto Cleanup;
                                                }
                                                RightTrim(szNextLine);//去掉最右边空格
                                                strcpy(pStr,szNextLine);//复制到斜杠所在位置
                                                free(szNextLine);
                                                goto ParseStr;//返回前面重新遍历这个字符串
                                        }
                                }
                                if(*pStr=='"')//如果找到双引号
                                {
                                        pStr++;
                                        while(*pStr)//向后查找对应的双引号
                                        {
                                                if(*pStr=='\\')//如果是斜杠就跳过这个字符
                                                {
                                                        pStr+=2;
                                                        continue;
                                                }
                                                if(*pStr=='"')//找到对应的双引号了
                                                        break;//跳出
                                                pStr++;
                                        }
                                        if(!(*pStr))//没找到则双引号不平衡
                                        {
                                                fprintf(stderr,
                                                        "%s(%u):Unbalanced quote\n",
                                                        argv,LineNo);
                                                goto Cleanup;
                                        }
                                }
                                if(*pStr=='\'')//如果找到单引号
                                {
                                        pStr++;
                                        while(*pStr)//向后查找对应的单引号
                                        {
                                                if(*pStr=='\\')//如果是斜杠就跳过这个字符
                                                {
                                                        pStr+=2;
                                                        continue;
                                                }
                                                if(*pStr=='\'')//找到对应的单引号了
                                                        break;//跳出
                                                pStr++;
                                        }
                                        if(!(*pStr))//没找到则双引号不平衡
                                        {
                                                fprintf(stderr,
                                                        "%s(%u):Unbalanced quote\n",
                                                        argv,LineNo);
                                                goto Cleanup;
                                        }
                                }
                        }


                        fputs(szLine,stdout);
                        fputc('\n',stdout);
                        free(szLine);
                }
                LineNo++;
        }

        fclose(fp);
        free(szLine);
        return 0;
Cleanup:
        fclose(fp);
        free(szLine);
        return 2;
}BIN:
SRC:

langzhe 发表于 2017-11-12 21:26:02

6666666666666666
页: [1]
查看完整版本: 【C】C语言写的给C语言源代码去掉注释的程序