简单的脚本来计算NLOC?

你知道一个简单的脚本来计算NLOC(netto代码行)。 该脚本应该计算C代码行。 它不应该只用括号计算空行或行。 但它也不需要过于精确。

我会使用awkcpp (预处理器)和wc来做到这一点。 awk删除所有大括号和空格,预处理器删除所有注释,wc计算行:

find . -name \*.cpp -o -name \*.h | xargs -n1 cpp -fpreprocessed -P | awk '!/^[{[:space:]}]*$/' | wc -l 

如果您想要包含评论:

 find . -name \*.cpp -o -name \*.h | xargs awk '!/^[{[:space:]}]*$/' | wc -l 

在网上看NLOC,我发现大多数是“非注释的代码行”。
您没有指定是否必须跳过评论…
因此,如果我坚持您当前的消息,Perl中的以下单行应该可以完成这项工作:

 perl -pe "s/^\s*[{}]?\s*\n//" Dialog.java | wc -l 

我可以扩展它来处理行注释:

 perl -pe "s#^\s*[{}]?\s*\n|^\s*//.*\n##" Dialog.java | wc -l 

也许

 perl -pe "s#^\s*(?:[{}]?\s*|//.*)\n##" Dialog.java | wc -l 

处理块注释稍微棘手(我不是Perl专家!)。

[编辑]得到它……第一部分可能会改进(更短)。 试验很有趣。

 perl -e "$x = join('', <>); $x =~ s#/\*.*?\*/##gs; print $x" Dialog.java | perl -pe "s#^\s*(?:[{}]?\s*|//.*)\n##" | wc -l 

PS。:我使用双引号,因为我在Windows上测试过……

查看Visual Studio的DPack插件。 它有任何解决方案/项目的统计报告。

不是脚本,但您可以尝试使用此命令行开源工具: NLOC

源监视器是免费的源分析软件。 它是Windows应用程序,但也可以使用命令行中的参数运行。

它可以分析C ++,C,C#,VB.NET,Java,Delphi,Visual Basic(VB6)或HTML。

Ohloh提供免费的Ohcount ,它可以计算代码和注释。

如果评论仍然存在,标准的unix工具就足够了:

 grep -x -v "[[:space:]}{]*" files.c | wc 

SLOCCOunt不是一个简单的脚本,并且比您需要的更多。 但是,它是已经提到的Ohcount和NLOC的强大替代品。 🙂

我通常只是这样做:

 grep -vc '^$' (my files) 

仅当空行真的为空(无空格)时才有效。 对我来说足够了。

Locmetrics效果很好。

这是一个简单的Perl脚本eLOC.pl :

 #!/usr/bin/perl -w # eLOC - Effective Lines of Code Counter # JFS (2005) # # $ perl eLOC.pl --help # use strict; use warnings; use sigtrap; use diagnostics; use warnings::register; no warnings __PACKAGE__; sub DEBUG { 0 } use English qw( -no_match_vars ) ; # Avoids regex performance penalty use Getopt::Long qw(:config gnu_getopt); use File::DosGlob 'glob'; use Pod::Usage; our $VERSION = '0.01'; # globals use constant NOTFILENAME => undef; my %counter = ( 'PHYS' => 0, 'ELOC' => 0, 'PURE_COMMENT' => 0, 'BLANK' => 0, 'LLOC' => 0, 'INLINE_COMMENT'=> 0, 'LOC' => 0, ); my %header = ( "eloc" => "eloc", "lloc" => "lloc", "loc" => "loc", "comment" => "comment", "blank" => "blank", "newline" => "newline", "logicline" => "lgcline", ); my %total = %counter; # copy my $c = \%counter; # see format below my $h = \%header; # see top format below my $inside_multiline_comment = 0; my $filename = NOTFILENAME; my $filecount = 0; my $filename_header = "file name"; # process input args my $version = ''; my $help = ''; my $man = ''; my $is_deterministic = ''; my $has_header = ''; print STDERR "Input args:'" if DEBUG; print STDERR (join("|",@ARGV),"'\n") if DEBUG; my %option = ('version' => \$version, 'help' => \$help, 'man' => \$man, 'deterministic' => \$is_deterministic, 'header' => \$has_header ); GetOptions( \%option, 'version', 'help', 'man', 'eloc|e', # print the eLOC counts 'lloc|s', # print the lLOC counts (code statements) 'loc|l' , # print the LOC counts (eLOC + lines of a single brace or parenthesis) 'comment|c' , # print the comments counts (count lines which contains a comment) 'blank|b' , # print the blank counts 'newline|n' , # print the newline count 'logicline|g' , # print the logical line count (= LOC + Comment Lines + Blank Lines) 'deterministic', # print the LOC determination for every line in the source file 'header', # print header line ) or invalid_options("$0: invalid options\nTry `$0 --help' for more information."); version() if $version; pod2usage(-exitstatus => 0, -verbose => 1) if $help ; pod2usage(-exitstatus => 0, -verbose => 2) if $man; # $has_header = 1 if $is_deterministic && $has_header eq ''; #format for print_loc_metric() my ($format, $format_top) = make_format(); print STDERR "format:\n" if DEBUG > 10; print STDERR $format if DEBUG > 10; eval $format; die $@ if $@; # $EVAL_ERROR if(DEBUG>10) { print STDERR ("format_top:\n", $format_top); } if( $has_header) { eval $format_top; die $@ if $@; # $EVAL_ERROR } # process files print STDERR ("Input args after Getopts():\n", join("|",@ARGV),"\n") if DEBUG > 10; expand_wildcards(); @ARGV = '-' unless @ARGV; foreach my $fn (@ARGV) { $filename = $fn; unless (open(IN, "<$filename")) { warn "$0: Unable to read from '$filename': $!\n"; next; } print STDERR "Scanning $filename...\n" if DEBUG; clear_counters(); generate_loc_metric(); $filecount++; print_loc_metric(); close(IN) or warn "$0: Could not close $filename: $!\n"; } # print total if($filecount > 1) { $filename = "total"; $c = \%total; print_loc_metric(); } exit 0; #------------------------------------------------- sub wsglob { my @list = glob; @list ? @list : @_; #HACK: defence from emtpy list from glob() } sub expand_wildcards { print STDERR ("Input args before expand_wildcards():\n", join("|",@ARGV),"\n") if DEBUG; { @ARGV = map( /['*?']/o ? wsglob($_) : $_ , @ARGV); } print STDERR ("Input args after expand_wildcards():\n", join("|",@ARGV),"\n") if DEBUG; } sub clear_counters { for my $name ( keys %counter) { $counter{$name} = 0; } } sub make_format { my $f = 'format STDOUT =' . "\n"; $f .= '# LOC, eLOC, lLOC, comment, blank, newline, logicline and filename' . "\n"; my $f_top = 'format STDOUT_TOP =' . "\n"; my $console_screen_width = (get_terminal_size())[0]; print STDERR '$console_screen_width=' . $console_screen_width ."\n" if DEBUG>10; $console_screen_width = 100 if $console_screen_width < 0; my $is_print_specifiers_set = ($option{"eloc"} or $option{"lloc"} or $option{"loc"} or $option{"comment"} or $option{"blank"} or $option{"newline"} or $option{"logicline"}); my %o = %option; my $fc = 0; if( $is_print_specifiers_set ) { $fc++ if $o{"eloc"}; $fc++ if $o{"lloc"}; $fc++ if $o{"loc"}; $fc++ if $o{"comment"}; $fc++ if $o{"blank"}; $fc++ if $o{"newline"}; $fc++ if $o{"logicline"}; if( $fc == 0 ) { die "$0: assertion failed: field count is zero" } } else { # default $fc = 7; $o{"loc"} = 1; $o{"eloc"} = 1; $o{"lloc"} = 1; $o{"comment"} = 1; $o{"blank"} = 1; $o{"newline"} = 1; $o{"logicline"} = 1; } if (DEBUG > 10) { while( (my ($name, $value) = each %{o}) ) { print STDERR "name=$name, value=$value\n"; } } # picture line my $field_format = '@>>>>>> '; my $field_width = length $field_format; my $picture_line = $field_format x $fc; # place for filename $picture_line .= '^'; $picture_line .= '<' x ($console_screen_width - $field_width * $fc - 2); $picture_line .= "\n"; $f .= $picture_line; $f_top .= $picture_line; # argument line $f .= '$$c{"LOC"}, ' ,$f_top .= '$$h{"loc"}, ' if $o{"loc"}; $f .= '$$c{"ELOC"}, ' ,$f_top .= '$$h{"eloc"}, ' if $o{"eloc"}; $f .= '$$c{"LLOC"}, ' ,$f_top .= '$$h{"lloc"}, ' if $o{"lloc"}; $f .= '$$c{"comment"}, ' ,$f_top .= '$$h{"comment"}, ' if $o{"comment"}; $f .= '$$c{"BLANK"}, ' ,$f_top .= '$$h{"blank"}, ' if $o{"blank"}; $f .= '$$c{"PHYS"}, ' ,$f_top .= '$$h{"newline"}, ' if $o{"newline"}; $f .= '$$c{"logicline"}, ',$f_top .= '$$h{"logicline"}, ' if $o{"logicline"}; $f .= '$filename' . "\n"; $f_top .= '$filename_header' . "\n"; # 2nd argument line for long file names $f .= '^'; $f .= '<' x ($console_screen_width-2); $f .= '~~' . "\n" .' $filename' . "\n"; $f .='.' . "\n"; $f_top .='.' . "\n"; return ($f, $f_top); } sub generate_loc_metric { my $is_concatinated = 0; LINE: while() { chomp; print if $is_deterministic && !$is_concatinated; # handle multiline code statements if ($is_concatinated = s/\\$//) { warnings::warnif("$0: '\\'-ending line concantinated"); increment('PHYS'); print "\n" if $is_deterministic; my $line = ; $_ .= $line; chomp($line); print $line if $is_deterministic; redo unless eof(IN); } # blank lines, including inside comments, don't move to next line here increment('BLANK') if( /^\s*$/ ); # check whether multiline comments finished if( $inside_multiline_comment && m~\*/\s*(\S*)\s*$~ ) { $inside_multiline_comment = 0; # check the rest of the line if it contains non-whitespace characters #debug $_ = $REDO_LINE . $1, redo LINE if($1); warnings::warnif("$0: expression '$1' after '*/' discarded") if($1); # else mark as pure comment increment('PURE_COMMENT'); next LINE; } # inside multiline comments increment('PURE_COMMENT'), next LINE if( $inside_multiline_comment ); # C++ style comment at the begining of line (except whitespaces) increment('PURE_COMMENT'), next LINE if( m~^\s*//~ ); # C style comment at the begining of line (except whitespaces) if ( m~^\s*/\*~ ) { $inside_multiline_comment = 1 unless( m~\*/~ ); increment('PURE_COMMENT'), next LINE; } # inline comment, don't move to next line here increment('INLINE_COMMENT') if ( is_inline_comment($_) ); # lLOC implicitly incremented inside is_inline_comment($) # increment('LOC') unless( /^\s*$/ ); # standalone braces or parenthesis next LINE if( /^\s*(?:\{|\}|\(|\))+\s*$/ ); # eLOC is not comments, blanks or standalone braces or parenthesis # therefore just increment eLOC counter here increment('ELOC'), next LINE unless( /^\s*$/ ); } continue { increment('PHYS'); print " [$.]\n" if $is_deterministic; # $INPUT_LINE_NUMBER } } sub print_loc_metric { $$c{'comment'} = $$c{'PURE_COMMENT'} + $$c{'INLINE_COMMENT'}; # LOC + Comment Lines + Blank Lines $$c{'logicline'} = $$c{'LOC'} + $$c{'comment'} + $$c{'BLANK'}; unless (defined $filename) { die "print_loc_metric(): filename is not defined"; } my $fn = $filename; $filename = "", $filename_header = "" unless($#ARGV); print STDERR ("ARGV in print_loc_metric:" , join('|',@ARGV), "\n") if DEBUG; write STDOUT; # replace with printf $filename = $fn; } sub increment { my $loc_type = shift; defined $loc_type or die 'increment(\$): input argument is undefined'; $counter{$loc_type}++; $total{$loc_type}++; print "\t#". $loc_type ."#" if $is_deterministic; } sub is_inline_comment { my $line = shift; defined $line or die 'is_inline_comment($): $line is not defined'; print "\n$line" if DEBUG > 10; # here: line is not empty, not begining both C and C++ comments signs, # not standalone '{}()', not inside multiline comment, # ending '\' removed (joined line created if needed) # Possible cases: # - no C\C++ comment signs => is_inline_comment = 0 # - C++ comment (no C comment sign) # * no quote characters => is_inline_comment = 1 # * at least one comment sign is not quoted => is_inline_comment = 1 # * all comment signs are quoted => is_inline_comment = 0 # - C comment (no C++ comment sign) # * no quote characters => is_inline_comment = 1, # ~ odd number of '/*' and '*/' => $inside_multiple_comment = 1 # ~ even number => $inside_multiple_comment = 0 # * etc... # - ... # algorithm: move along the line from left to right # rule: quoted comments are not counted # rule: quoted by distinct style quotes are not counted # rule: commented quotes are not counted # rule: commented distinct style comments are not counted # rule: increment('LLOC') if not-quoted, not-commented # semi-colon presents in the line except that two # semi-colon in for() counted as one. # $_ = $line; #hack: $_ = $line inside sub # state my %s = ( 'c' => 0, # c slash star - inside c style comments 'cpp' => 0, # c++ slash slash - inside C++ style comment 'qm' => 0, # quoted mark - inside quoted string 'qqm' => 0, # double quoted - inside double quoted string ); my $has_comment = 0; # find state LOOP: { /\G\"/gc && do { # match double quote unless( $s{'qm'} || $s{'c'} || $s{'cpp'} ) { # toggle $s{'qqm'} = $s{'qqm'} ? 0 : 1; } redo LOOP; }; /\G\'/gc && do { # match single quote unless( $s{'qqm'} || $s{'c'} || $s{'cpp'} ) { # toggle $s{'qm'} = $s{'qm'} ? 0 : 1; } redo LOOP; }; m~\G//~gc && do { # match C++ comment sign unless( $s{'qm'} || $s{'qqm'} || $s{'c'} ) { # on $has_comment = 1; $s{'cpp'} = 1; } redo LOOP; }; m~\G/\*~gc && do { # match begining C comment sign unless( $s{'qm'} || $s{'qqm'} || $s{'cpp'} ) { # on $has_comment = 1; $s{'c'} = $s{'c'} ? 1 : 1; } redo LOOP; }; m~\G\*/~gc && do { # match ending C comment sign unless( $s{'qm'} || $s{'qqm'} || $s{'cpp'} ) { # off if( $s{'c'} ) { $s{'c'} = 0; } else { die 'is_inline_comment($): unexpected c style ending comment sign'. "\n'$line'"; } } redo LOOP; }; /\Gfor\s*\(.*\;.*\;.*\)/gc && do { # match for loop unless( $s{'qm'} || $s{'qqm'} || $s{'cpp'} || $s{'c'} ) { # not-commented, not-quoted semi-colon increment('LLOC'); } redo LOOP; }; /\G\;/gc && do { # match semi-colon unless( $s{'qm'} || $s{'qqm'} || $s{'cpp'} || $s{'c'} ) { # not-commented, not-quoted semi-colon # not inside for() loop increment('LLOC'); } redo LOOP; }; /\G./gc && do { # match any other character # skip 1 character redo LOOP; }; /\G$/gc && do { # match end of the line last LOOP; }; #default die 'is_inline_comment($): unexpected character in the line:' . "\n'$line'"; } # apply state $inside_multiline_comment = $s{'c'}; return $has_comment; } sub version { # TODO: version implementation print <<"VERSION"; NAME v$VERSION Written by AUTHOR COPYRIGHT AND LICENSE VERSION exit 0; } sub invalid_options { print STDERR (@_ ,"\n"); exit 2; } sub get_terminal_size { my ($wchar, $hchar) = ( -1, -1); my $win32console = <<'WIN32_CONSOLE'; use Win32::Console; my $CONSOLE = new Win32::Console(); ($wchar, $hchar) = $CONSOLE->MaxWindow(); WIN32_CONSOLE eval($win32console); return ($wchar, $hchar) unless( $@ ); warnings::warnif($@); # $EVAL_ERROR my $term_readkey = <<'TERM_READKEY'; use Term::ReadKey; ($wchar,$hchar, $wpixels, $hpixels) = GetTerminalSize(); TERM_READKEY eval($term_readkey); return ($wchar, $hchar) unless( $@ ); warnings::warnif($@); # $EVAL_ERROR my $ioctl = <<'IOCTL'; require 'sys/ioctl.ph'; die "no TIOCGWINSZ " unless defined &TIOCGWINSZ; open(TTY, "+ B<[>OPTIONB<]...> B<[>FILEB<]...> Print LOC, eLOC, lLOC, comment, blank, newline and logicline counts for each FILE, and a total line if more than one FILE is specified. See L for more info, use `eloc --man'. -e, --eloc print the {E}LOC counts -s, --lloc print the lLOC counts (code {S}tatements) -l, --loc print the {L}OC counts (eLOC + lines of a single brace or parenthesis) -c, --comment print the {C}omments counts (count lines which contains a comment) -b, --blank print the {B}lank counts -n, --newline print the {N}ewline count -g, --logicline print the lo{G}ical line count (= LOC + Comment Lines + Blank Lines) --deterministic print the LOC determination for every line in the source file --header print header line --help display this help and exit --man display full help and exit --version output version information and exit With no FILE, or when FILE is -, read standard input. Metrics counted by the program are based on narration from http://msquaredtechnologies.com/m2rsm/docs/rsm_metrics_narration.htm =for TODO: Comment Percent = Comment Line Count / Logical Line Count ) x 100 =for TODO: White Space Percentage = (Number of spaces / Number of spaces and characters) * 100 =head1 DESCRIPTION eLOC is a simple LOC counter. See L. =head2 LOC Specification =over 1 =item LOC Lines Of Code = eLOC + lines of a single brace or parenthesis =item eLOC An effective line of code or eLOC is the measurement of all lines that are not comments, blanks or standalone braces or parenthesis. This metric more closely represents the quantity of work performed. RSM introduces eLOC as a metrics standard. See http://msquaredtechnologies.com/m2rsm/docs/rsm_metrics_narration.htm =item lLOC Logical lines of code represent a metrics for those line of code which form code statements. These statements are terminated with a semi-colon. The control line for the "for" loop contain two semi-colons but accounts for only one semi colon. See http://msquaredtechnologies.com/m2rsm/docs/rsm_metrics_narration.htm =item comment comment = pure comment + inline comment =over =item pure comment Comment lines represent a metrics for pure comment line without any code in it. See L. =item inline comment Inline comment line is a line which contains both LOC line and pure comment. Inline comment line and pure comment line (see L) are mutually exclusive, that is a given physical line cannot be an inline comment line and a pure comment line simultaneously. =over =item Example: static const int defaultWidth = 400; // value provided in declaration =back =back =item blank Blank line is a line which contains at most whitespaces. Blank lines are counted inside comments too. =item logicline The logical line count = LOC + Comment Lines + Blank Lines =back =head1 KNOWN BUGS AND LIMITATIONS =over =item It supports only C/C++ source files. =item Comments inside for(;;) statements are not counted =over =item Example: for(int i = 0; i < N /*comment*/; i++ ); #LLOC# #LLOC# #LOC# #ELOC# #PHYS# [1] =back =item '\'-ending lines are concatinated ( though newline count is valid) =item Input from stdin is not supported in the case the script is envoked solely by name without explicit perl executable. =item Wildcards in path with spaces are not supported (like GNU utilities). =back =over =begin fixed =item Limitation: single source file Only one source file at time supported =item Limitation: LLOC is unsupported The logical lines of code metric is unsupported. =item missed inline comment for C style comment #include  /* comment */ #ELOC# #PHYS# [2] But must be #include  /* comment */ #INLINE_COMMENT# #ELOC# #PHYS# [2] =item wrong LOC type for the code after '*/' /* another #PURE_COMMENT# #PHYS# [36] trick #PURE_COMMENT# #PHYS# [37] */ i++; #PURE_COMMENT# #PHYS# [38] In the last line must be #INLINE_COMMENT# #PHYS# [38] =end fixed =back =head1 SEE ALSO Metrics counted by the program are based on narration from L =cut 

以下脚本将获取与给定目录中的模式匹配的所有文件的计数。

#START OF SCRIPT

var str文件
var str dir

set $ files =“* .cpp”#<=====================在此处设置文件名模式。
set $ dir =“C:/ myproject”#<=====================在此处设置项目目录。

#获取变量fileList中的文件列表。
var str fileList
find -rn files($ files)dir($ dir)> $ fileList

#声明我们将保存单个文件计数的变量。
var int c#所有行
var int nb#非空行

#声明变量,我们将保存所有文件的总计数。
var int totalc#sum-total of all lines
var int totalnb#sum-total所有非空行

#声明我们将存储文件计数的变量。
var int fileCount

#我们将存储当前正在处理的文件的名称,如下所示。
var str文件

#逐个通过$ fileList文件。
while($ fileList <>“”)

#解压缩下一个文件。
lex“1”$ fileList> $ file

#检查这是否是平面文件。 我们对目录不感兴趣。
af $ file> null#我们不想看到输出。
#我们只想设置$ ftype变量。
if($ ftype ==“f”)

#是的,这是一个平面文件。

  # Increment file count.
set $fileCount = $fileCount+1
# Collect the content of $file in $content
var str content # Content of one file at a time
repro $file >$content
# Get count and non-blank count.
set $c={len -e $content}
set $nb={len $content}
echo -e "File: " $file ", Total Count: " $c ", Non-blank Count: " $nb
# Update total counts.
set $totalc = $totalc + $c
set $totalnb = $totalnb + $nb

DONE
万一

DONE

显示总和

回声“************************************************ ************************************************** *********”
echo“所有行的总计数:\ t”$ totalc“,\ t总非空行数:\ t”$ totalnb“,总文件数:”$ fileCount
回声“************************************************ ************************************************** *********”

#END OF SCRIPT

如果您想要仅在2008年修改的文件中的行数,请添加($ fmtime> =“2008”)等。

如果您没有biterscripting,请从.com获取。

不是一个简单的脚本,但CCCC (C和C ++代码计数器)已经存在了一段时间,它对我来说很有用。

我有一个名为scc的程序,它可以scc C scc (和C ++注释,但是C99它们是相同的)。 应用它加上一个filter来删除空白行,如果需要,还可以包含仅包含打开和关闭大括号的行,以生成行计数。 我已经在内部项目中使用了它 – 不需要打开/关闭大括号。 这些脚本比较复杂,比较了存储在ClearCase中的两个不同版本的实际项目的源代码。 他们还对添加和删除的文件以及在常用文件中添加和删除的行进行了统计。

不计算括号会产生很大的不同:

 Black JL: co -q -p scc.c | scc | sed '/^[ ]*$/d' | wc -l 208 Black JL: co -q -p scc.c | scc | sed '/^[ {}]*$/d' | wc -l 144 Black JL: co -p -q scc.c | wc -l 271 Black JL: 

所以,你的规则下有144行; 208计算开闭线; 271计算一切。

Lemme知道你是否想要scc的代码(在gmail dot com上发送电子邮件到最后一个点)。 这是13 KB的gzip压缩文件,包括手册页,酷刑测试和一些库文件。


@litb评论说’ cpp -fpreprocessed -P file ‘处理注释的剥离。 它主要是。 但是,当我在SCC的压力测试中运行时,它抱怨(在我看来)它不应该:

 SCC has been trained to handle 'q' single quotes in most of the aberrant forms that can be used. '\0', '\', '\'', '\\ n' (a valid variant on '\n'), because the backslash followed by newline is elided by the token scanning code in CPP before any other processing occurs. 

当GCC 4.3.2的CPP对此进行处理时,它会抱怨(警告):

 SCC has been trained to handle 'q' single quotes in most of :2:56: warning: missing terminating ' character the aberrant forms that can be used. '\0', '\', '\'', '\\ :3:27: warning: missing terminating ' character n' (a valid variant on '\n'), because the backslash followed by newline is elided by the token scanning code in CPP before any other processing occurs. 

第5.1.1.2节C99标准的翻译阶段说:

翻译语法规则的优先顺序由以下阶段指定。( 脚注5

  1. 如果需要,物理源文件多字节字符以实​​现定义的方式映射到源字符集(引入行尾指示符的换行符)。 Trigraph序列由相应的单字符内部表示替换。

  2. 删除反斜杠字符()后面紧跟一个新行字符的每个实例,拼接物理源代码行以形成逻辑源代码行。 只有任何物理源线上的最后一个反斜杠才有资格成为这种拼接的一部分。 非空的源文件应以换行符结尾,在进行任何此类拼接之前,该换行符不应立即以反斜杠字符开头。

脚注5是:

(5)实施应表现为好像发生这些单独的阶段,即使许多通常在实践中折叠在一起。

因此,在我看来,CPP在示例文本中error handling了第二阶段。 或者,至少,警告不是我想要的 – 构造是有效的C并且保证警告是不言自明的。

当然,这是一个边缘案例,允许额外的警告。 但这会让我的生活日光黯然失色。 如果我没有自己的,可能更好的工作工具,那么使用’ cpp -fpreprocessed -P ‘会这样做 – 这是一个极端的边缘情况,我在抱怨(并且,辩论可能是合理的更有可能是存在问题而不是 – 虽然更好的启发式会观察到线被拼接而且结果是合法的单个字符常量,因此应该抑制投诉;如果结果不是合法的单个字符不断,然后投诉应该产生。(在我的测试案例中 – 无可否认是一次折磨测试 – CPP产生了13个问题,主要与我抱怨的那个问题有关,SCC正确地产生了2.)

(我观察到’ -P ‘设法在省略选项时出现的输出中抑制’ #line ‘指令。)