有没有一种简便的方法可以在不进行任何预处理的情况下从C / C ++源文件中删除注释。(即,我认为您可以使用gcc -E,但这将扩展宏。)我只希望除去注释的源代码,没有其他更改。
编辑:
偏爱现有工具。我不想自己用正则表达式编写代码,我预见代码中会出现太多惊喜。
有没有一种简便的方法可以在不进行任何预处理的情况下从C / C ++源文件中删除注释。(即,我认为您可以使用gcc -E,但这将扩展宏。)我只希望除去注释的源代码,没有其他更改。
编辑:
偏爱现有工具。我不想自己用正则表达式编写代码,我预见代码中会出现太多惊喜。
error: pasting "/" and "/" does not give a valid preprocessing token
-这是可以预期的,因为注释的删除发生在预处理之前
Answers:
在您的源文件上运行以下命令:
gcc -fpreprocessed -dD -E test.c
感谢KennyTM找到正确的标志。这是完整性的结果:
test.c:
#define foo bar
foo foo foo
#ifdef foo
#undef foo
#define foo baz
#endif
foo foo
/* comments? comments. */
// c++ style comments
gcc -fpreprocessed -dD -E test.c
:
#define foo bar
foo foo foo
#ifdef foo
#undef foo
#define foo baz
#endif
foo foo
#define foo bar\nfoo foo foo
gcc -fpreprocessed -dM -E test.c
以获取#define
-s,但是它们不在原始位置。
#include
d文件,并用空白行替换了注释行,而不是删除注释。FWIW sed和gcc的组合对我来说一直很完美,请参见stackoverflow.com/a/13062682/1745001。
这取决于您的评论有多不正确。我有一个scc
剥离C和C ++注释的程序。我也有一个测试文件,我尝试了GCC(在MacOS X上为4.2.1)并使用了当前选择的答案中的选项-而且GCC在某些令人费解的注释中似乎做得并不完美。测试用例。
考虑一下测试用例(子集-总共135行中的36行):
/\
*\
Regular
comment
*\
/
The regular C comment number 1 has finished.
/\
\/ This is not a C++/C99 comment!
This is followed by C++/C99 comment number 3.
/\
\
\
/ But this is a C++/C99 comment!
The C++/C99 comment number 3 has finished.
/\
\* This is not a C or C++ comment!
This is followed by regular C comment number 2.
/\
*/ This is a regular C comment *\
but this is just a routine continuation *\
and that was not the end either - but this is *\
\
/
The regular C comment number 2 has finished.
This is followed by regular C comment number 3.
/\
\
\
\
* C comment */
在我的Mac上,GCC(gcc -fpreprocessed -dD -E subset.c
)的输出为:
/\
*\
Regular
comment
*\
/
The regular C comment number 1 has finished.
/\
\/ This is not a C++/C99 comment!
This is followed by C++/C99 comment number 3.
/\
\
\
/ But this is a C++/C99 comment!
The C++/C99 comment number 3 has finished.
/\
\* This is not a C or C++ comment!
This is followed by regular C comment number 2.
/\
*/ This is a regular C comment *\
but this is just a routine continuation *\
and that was not the end either - but this is *\
\
/
The regular C comment number 2 has finished.
This is followed by regular C comment number 3.
/\
\
\
\
* C comment */
“ scc”的输出为:
The regular C comment number 1 has finished.
/\
\/ This is not a C++/C99 comment!
This is followed by C++/C99 comment number 3.
/\
\
\
/ But this is a C++/C99 comment!
The C++/C99 comment number 3 has finished.
/\
\* This is not a C or C++ comment!
This is followed by regular C comment number 2.
The regular C comment number 2 has finished.
This is followed by regular C comment number 3.
“ scc -C”(可识别双斜杠注释)的输出为:
The regular C comment number 1 has finished.
/\
\/ This is not a C++/C99 comment!
This is followed by C++/C99 comment number 3.
The C++/C99 comment number 3 has finished.
/\
\* This is not a C or C++ comment!
This is followed by regular C comment number 2.
The regular C comment number 2 has finished.
This is followed by regular C comment number 3.
尽管Git版本创建于2017年1月18日(在美国/太平洋时区),但SCC的当前版本为6.60(日期为2016-06-12)。该代码可从GitHub上的https://github.com/jleffler/scc-snapshots获得。您还可以找到先前发行版(4.03、4.04、5.05)和两个预发行版(6.16、6.50)的快照—均已标记release/x.yz
。
该代码仍然主要是在RCS下开发的。我仍在研究如何使用子模块或类似的机制来处理常见的库文件,例如stderr.c
和stderr.h
(也可以在https://github.com/jleffler/soq中找到)。
SCC版本6.60试图了解C ++ 11,C ++ 14和C ++ 17的构造,例如二进制常量,数字标点,原始字符串和十六进制浮点数。默认为C11模式操作。(请注意,上述-C
标志的含义在答案正文中描述的4.0x版本和当前最新版本的6.60之间切换。)
gcc -fpreprocessed -dD -E对我不起作用,但是此程序可以实现:
#include <stdio.h>
static void process(FILE *f)
{
int c;
while ( (c=getc(f)) != EOF )
{
if (c=='\'' || c=='"') /* literal */
{
int q=c;
do
{
putchar(c);
if (c=='\\') putchar(getc(f));
c=getc(f);
} while (c!=q);
putchar(c);
}
else if (c=='/') /* opening comment ? */
{
c=getc(f);
if (c!='*') /* no, recover */
{
putchar('/');
ungetc(c,f);
}
else
{
int p;
putchar(' '); /* replace comment with space */
do
{
p=c;
c=getc(f);
} while (c!='/' || p!='*');
}
}
else
{
putchar(c);
}
}
}
int main(int argc, char *argv[])
{
process(stdin);
return 0;
}
有一个stripcmt程序可以执行以下操作:
StripCmt是一个用C编写的简单实用程序,用于从C,C ++和Java源文件中删除注释。在Unix文本处理程序的传统中,它既可以用作FIFO(先进先出)过滤器,也可以在命令行上接受参数。
(根据hlovdal的回答:有关此Python代码的问题)
int /* comment // */ main()
。
// comment out next line \
这是一个Perl脚本,用于删除//单行和/ *多行* /注释
#!/usr/bin/perl
undef $/;
$text = <>;
$text =~ s/\/\/[^\n\r]*(\n\r)?//g;
$text =~ s/\/\*+([^*]|\*(?!\/))*\*+\///g;
print $text;
它需要您的源文件作为命令行参数。将脚本保存到文件中,例如说remove_comments.pl并使用以下命令调用它:perl -w remove_comments.pl [您的源文件]
希望对您有所帮助
"/*"
或"//"
等的字符串。
我也有这个问题。我发现此工具(Cpp-Decomment)对我有用。但是,它忽略注释行是否延伸到下一行。例如:
// this is my comment \
comment continues ...
在这种情况下,我无法在程序中找到方法,因此只能搜索被忽略的行并手动进行修复。我相信会有一个选择,或者您可以更改程序的源文件来这样做。
因为您使用C,所以您可能想使用对C来说“自然”的东西。您可以使用C预处理器来删除注释。下面给出的示例与GCC中的C预处理器一起使用。它们也应该与其他C处理器相同或相似的方式工作。
对于C,使用
cpp -dD -fpreprocessed -o output.c input.c
它还可用于从JSON删除注释,例如:
cpp -P -o - - <input.json >output.json
如果你的C预处理不能直接访问,你可以尝试更换cpp
使用cc -E
,这就要求C编译器,告诉它的预处理阶段之后停止。如果您的C编译器二进制文件不是cc
,则可以用cc
C编译器二进制文件的名称替换,例如clang
。请注意,并非所有预处理器都支持-fpreprocessed
。
我使用标准的C库编写了一个C程序,大约200行,其中删除了C源代码文件的注释。 qeatzy / removecomments
void init(/* do initialization */) {...}
"
和尊重C字符串文字\"
。\
,则当前行是前一行的一部分。我使用包含很多注释的最大cpython源代码进行了测试。在这种情况下,它可以正确,快速地完成工作,比gcc快2-5
time gcc -fpreprocessed -dD -E Modules/unicodeobject.c > res.c 2>/dev/null
time ./removeccomments < Modules/unicodeobject.c > result.c
/path/to/removeccomments < input_file > output_file
我知道已经晚了,但是我想我应该分享我的代码和我第一次尝试编写编译器。
注意:这不"\*/"
包括多行注释中的内容,例如/\*...."*/"...\*
。再说一次,gcc 4.8.1也没有。
void function_removeComments(char *pchar_sourceFile, long long_sourceFileSize)
{
long long_sourceFileIndex = 0;
long long_logIndex = 0;
int int_EOF = 0;
for (long_sourceFileIndex=0; long_sourceFileIndex < long_sourceFileSize;long_sourceFileIndex++)
{
if (pchar_sourceFile[long_sourceFileIndex] == '/' && int_EOF == 0)
{
long_logIndex = long_sourceFileIndex; // log "possible" start of comment
if (long_sourceFileIndex+1 < long_sourceFileSize) // array bounds check given we want to peek at the next character
{
if (pchar_sourceFile[long_sourceFileIndex+1] == '*') // multiline comment
{
for (long_sourceFileIndex+=2;long_sourceFileIndex < long_sourceFileSize; long_sourceFileIndex++)
{
if (pchar_sourceFile[long_sourceFileIndex] == '*' && pchar_sourceFile[long_sourceFileIndex+1] == '/')
{
// since we've found the end of multiline comment
// we want to increment the pointer position two characters
// accounting for "*" and "/"
long_sourceFileIndex+=2;
break; // terminating sequence found
}
}
// didn't find terminating sequence so it must be eof.
// set file pointer position to initial comment start position
// so we can display file contents.
if (long_sourceFileIndex >= long_sourceFileSize)
{
long_sourceFileIndex = long_logIndex;
int_EOF = 1;
}
}
else if (pchar_sourceFile[long_sourceFileIndex+1] == '/') // single line comment
{
// since we know its a single line comment, increment file pointer
// until we encounter a new line or its the eof
for (long_sourceFileIndex++; pchar_sourceFile[long_sourceFileIndex] != '\n' && pchar_sourceFile[long_sourceFileIndex] != '\0'; long_sourceFileIndex++);
}
}
}
printf("%c",pchar_sourceFile[long_sourceFileIndex]);
}
}
/*
处理完毕,下一个无间隔的字符序列将*/
终止注释;注释中没有转义机制-这可能就是您GCC也不处理它的意思。您的代码存在问题"/* Magritte notes: Ceci n'est pas une commentaire */"
(因为它是字符串文字,而不是注释,但是他在谈论管道而不是注释)。
#include<stdio.h>
{
char c;
char tmp = '\0';
int inside_comment = 0; // A flag to check whether we are inside comment
while((c = getchar()) != EOF) {
if(tmp) {
if(c == '/') {
while((c = getchar()) !='\n');
tmp = '\0';
putchar('\n');
continue;
}else if(c == '*') {
inside_comment = 1;
while(inside_comment) {
while((c = getchar()) != '*');
c = getchar();
if(c == '/'){
tmp = '\0';
inside_comment = 0;
}
}
continue;
}else {
putchar(c);
tmp = '\0';
continue;
}
}
if(c == '/') {
tmp = c;
} else {
putchar(c);
}
}
return 0;
}
该程序在以下两个条件下运行://和/ / ..... /
int main(void)
。2.它不处理字符串文字和字符常量中的注释定界符。3.删除单个/
字符(尝试在其自己的源代码上运行)。