【发布时间】:2013-10-14 19:49:57
【问题描述】:
我正在从 K&R 书中学习 C,对于第一章的练习 1.23,我必须编写一个程序,在给定用户输入的一些 C 代码的情况下删除所有 cmets。这是我到目前为止完成的程序。我可以对其进行任何改进吗?
/**
Tuesday, 10/07/2013
Exercise 1.23
Write a program to remove all comments from a C
program. Don't forget to handle quoted strings
and character constants properly. C comments
don't nest.
**/
#include <stdio.h>
#define MAX_LENGTH 65536
#define NOT_IN_COMMENT 0
#define SINGLE_COMMENT 1
#define MULTI_COMMENT 2
main()
{
char code[MAX_LENGTH]; /* Buffer that stores the inputted code */
int size = 0; /* Length of the inputted code */
int loop; /* Integer used for the for loop */
char c; /* Character to input into */
int status = NOT_IN_COMMENT; /* Are we in a comment? What type? */
int in_string = 0; /* Are we inside of a string constant? */
char last_character; /* Value of the last character */
/* Input all code into the buffer until escape sequence pressed */
while ((c = getchar()) != EOF)
code[size++] = c;
code[size] = '\0';
/* Remove all comments from the code and display results to user */
for (loop = 0; loop < size; loop++) {
char current = code[loop];
if (in_string) {
if (current == '"') in_string = 0;
putchar(current);
}
else {
if (status == NOT_IN_COMMENT) {
if (current == '"') {
putchar(current);
in_string = 1;
continue;
}
if (current == '/' && last_character == '/') status = SINGLE_COMMENT;
else if (current == '*' && last_character == '/') status = MULTI_COMMENT;
else if (current != '/' || (current == '/' && loop < size-1 && !(code[loop+1] == '/' || code[loop+1] == '*'))) putchar(current);
}
else if (status == SINGLE_COMMENT) {
if (current == '\n') {
status = NOT_IN_COMMENT;
putchar('\n');
}
}
else if (status == MULTI_COMMENT) {
if (current == '/' && last_character == '*') status = NOT_IN_COMMENT;
}
}
last_character = current;
}
}
【问题讨论】:
-
首先,我会说将状态 (
NOT_IN_COMMENT,SINGLE_COMMENT,MULTI_COMMENT) 设为枚举并将 in_string 设为另一个状态。或者当你点击其中一个(",//,/*)时,直接烧掉字符,直到你在没有完整循环的情况下打完它。 -
您需要认识到“K&R C”是一种死语言。有许多改进导致了现代 C。特别是,请使用
int main( void )或int main( int argc, char **argv ) -
将
main()更改为int main(void)并在末尾添加return 0;,代码编译干净(这是一个好兆头),并从其源代码中删除所有cmets(良好的开始)。但是,"\"/*"可能会混淆您的字符串处理代码,因为您没有考虑反斜杠。以反斜杠结尾的 C++ 注释行继续到下一行。诸如'/*'之类的字符常量是不可移植的,但它是有效的,并且会在工作中抛出一个扳手。我不会为关于三元组的谩骂而烦恼。此外,斜杠、反斜杠、换行符、星号序列确实会开始/*注释。 -
顺便说一句,Remove comments from C/C++ code 有一些 C 注释剥离器酷刑测试“代码”。
-
如果你制作吃 cmets / 多行 cmets / 字符串的短循环并根除
NOT_IN_COMMENT,SINGLE_COMMENT,MULTI_COMMENT会更有效,因为这将使你的函数更快(相当分支和跳跃将被保存)。仅当您没有一次将整个字符串保存在内存中并且需要将状态传递给下一个函数调用时,这些才有意义。
标签: c