目录
为什么要写这篇
前几天因为移植,遇到注释乱码问题,因为最终确定改不回来了,干脆把乱码注释都删掉,就用C语言实现了。
我也是参考了网上的一篇文章,但是和他/她的不同点是,我按照自己的思路对程序重新实现了,思路不够清晰的话,即使是很简短的代码看起来也是相当费劲的一件事。同时根据自己的习惯写上了注释,我对写注释这件事还是相当执着的,即使在此花费一定量的时间。
同时为了实用性,可以传入要删除注释的文件名,根据我之前做的那个将快递单号传输到Excel 的方式,给要保存的文件重新命名,与那个不同的是,这个除了可以传入要删除注释的文件名外,还可以传入要保存的文件名。
可以传入文件名,那文件名如何传递进去呢?
熟悉main函数传参数的小伙伴应该知道通过命令行,可执行文件后面写入要传入的参数,然后回车就好了。这应该在嵌入式Linux的程序上比较常见。传入的字符串是文件名的话就可以将 待修改的文件名传进去,同理也可以将要保存的文件名传进去。

关于可以不传入要保存的文件名,那是如何实现的呢?
首先要知道要要保存的文件名与要修改的源文件的关系,通过要修改的源文件的文件名确定要保存的文件名。
可以传入文件名的好处是什么?
如果文件名是源文件内的一个字符串变量,那么就需要每次都修改然后重新编译,就需要使用者配置相应的编译环境。而如今这种已经生成可执行文件,即使没有配置相应的编译环境,也可以执行,只需要cmd命令窗口进入相应文件目录,然后传入文件名参数就可以了。这一步即使是配置相应编译环境也需要这么执行。
这是个实用的可执行文件吗?
通过cmd命令窗口进入相应的目录,然后手动输入,回车。。。那太不友好了,还好我知道这问题如何解决,bat脚本,通过鼠标右键的编辑打开bat脚本文件,输入要修改的文件名,保存后双击就会生成删除注释后的源文件了。至于为什么是main.exe 那就是Makefile决定的了。Makefile的打开方式就不能通过鼠标右键的编辑了。我常用的是VS code 和 Notepad++
Makefile中内容如下,想了解为什么这么写网上应该有大把的资料吧,比如C语言中文网
如果报出某种警告的话,把bat脚本文件中make那一行删掉,这是编译生成可执行文件用的,没有配置编译环境这一步是不需要的。
后期可改进的
更理想的功能是想要删除注释的源文件放在同一目录下,然后双击运行bat脚本,就生成了删除注释后的源文件。
或者将DeleteNotes.exe 和 DeleteNotes.bat 放在一个目录下,该目录下的所有源文件都删除注释,新生成一个文件夹,用于存放删除注释后的源文件。
我把实现逻辑写在注释里了,可以结合着代码理解一下。文件我上传到CSDN上了:DeleteNotes.zip,有需要的可以拿来试试。
/**
* @file DeleteNotes.c
* @brief 删除C语言文件中的所有注释
*
* @par 修改日志:
* <table>
* <tr><th>Date <th>Version <th>Author <th>Description
* <tr><td>2021-02-01 <td>1.0.0 <td>Lv_*_Guang <td>修改内容描述
* </table>
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <stdbool.h>
#define MAX_LENGTH 300
/**
* main
* @brief 查找// 和 / * * / , 然后删除注释
* @param argc 参数描述: 参数个数,以空格分隔得到,不需要输入
* @param argv 参数描述: 字符串数组
* @retval int 返回值描述: 无
* @note 如果参数个数小于2,说明没有没有文件要处理,提示并返回
* @note 如果参数个数为2,第二个字符串为要操作的文件名
* @note 如果参数个数大于2,说明第三个字符串为要保存的文件名
* @note 尝试打开和 写入文件(写入时若文件不存在则自动创建)
* @note 以MAX_LENGTH 为缓存大小,个人试着一行代码基本不会超过这些字符,超过也无所谓
* @note fgets 获取MAX_LENGTH - 1 个字符,最后一个字符要留给'\0' ,如果遇到换行符'\n',即使缓存未满也不再读取,
* @note 可能是因为'\n' 后面紧接着是'\0',C标准库中字符串操作的函数都将'\0' 作为结束符
* @note 查询到特定字符后将原本读取的某些字符串判定为注释,然后清0
* @note 将剩余字符写入到要保存的文件中
*/
int main(int argc, char* argv[])
{
FILE *fp, *fp1;
char str[MAX_LENGTH] = "";
bool multi_lines_notes = false;
char str_open_file[30] = "";
char str_save_file[30] = "";
if(argc <= 1)
{
printf("There are no files to modify! \n");
exit(0);
}else if(argc <= 2)
{
char str_filename[30] = "";
char str_fileextension[30] = "";
sprintf(str_open_file, "%s", argv[1]);
char* suffix = strrchr(str_open_file, '.');
memcpy(str_filename, str_open_file, strlen(str_open_file) - strlen(suffix));
memcpy(str_fileextension, suffix, strlen(suffix));
sprintf(str_save_file, "%s%s%s", str_filename, "_modify", str_fileextension);
printf("str_open_file is : %s \n", str_open_file);
printf("str_save_file is : %s \n", str_save_file);
}else
{
sprintf(str_open_file, "%s", argv[1]);
sprintf(str_save_file, "%s", argv[2]);
printf("str_open_file is : %s \n", str_open_file);
printf("str_save_file is : %s \n", str_save_file);
}
if ((fp = fopen(str_open_file, "r")) == NULL)
{
printf("open file error!\n");
exit(0);
}
if ((fp1 = fopen(str_save_file, "w")) == NULL)
{
printf("new_built file error!\n");
exit(0);
}
while (fgets(str, MAX_LENGTH - 1, fp) != NULL) //缓冲区满返回,遇到换行符返回
{
for (uint16_t i = 0; i < MAX_LENGTH - 1; i++)
{
if (str[i] == '/' && str[i - 1] == '/') ///< //
{
memset(str + i - 1, '\0', MAX_LENGTH - i);
str[i - 1] = '\n';
str[i] = '\0';
}
if (str[i] == '*' && str[i - 1] == '/') ///< /*
{
memset(str, '\0', i);
multi_lines_notes = true;
fputs(str, fp1);
}
if (str[i] == '/' && str[i - 1] == '*') ///< */
{
memset(str, '\0', i);
multi_lines_notes = false;
}
}
if (! multi_lines_notes)
{
fputs(str, fp1);
}
}
fclose(fp);
fclose(fp1);
return 0;
}