2017-01-18 22 views
2

我开始编码C在vim和我有一些问题。加入C行[奇怪的输出不兼容文档]

反斜杠旨在联接线,但是当我尝试写:

ret\ 
urn 0; 

我得到

return 
    0; 

,当我urn;前加空格,留样,如果没有加入。

ret\ 
    urn 0; 

它保持那样。

为什么在第二种情况下我不明白return 0;

ret 
    urn 0; 

代码: enter image description here

CPP输出:

enter image description here

命令:

gcc -E -Wall -Wextra -Wimplicit -pedantic -std=c99 main.c -o output.i 

GCC 5.4, Vim的7.4

+0

什么问题? –

+0

重现问题的代码在哪里? –

+0

不需要代码。我不在乎我正在谈论的预处理器阶段的代码执行! – Sabrina

回答

1

白色空间是令牌隔板。仅仅因为你分割线并不意味着白色空间将被忽略。

编译器看到的东西就像ret urn;。哪个是无效的C,因为它可能是之前没有定义的两个标记,也不是有效的表达式。

关键字必须写为不带空格的单个令牌。

现在,当你这样做:

ret\ 
urn; 

反斜杠后跟一个换行符在早期平移阶段被删除,下一行追加。如果行在开始处没有空格,则结果是编译器可以理解为关键字return的有效标记。


长话短说,你似乎在询问specific behavior for GCC。这看起来像一个编译器错误。由于clang does the expected thing(虽然行数保持不变):

clang -E -Wall -Wextra -Wimplicit -pedantic -std=c99 -x c main.cpp 
# 1 "main.cpp" 
# 1 "<built-in>" 1 
# 1 "<built-in>" 3 
# 316 "<built-in>" 3 
# 1 "<command line>" 1 
# 1 "<built-in>" 2 
# 1 "main.cpp" 2 
int main(void) { 
    ret urn 0; 

} 

这似乎并不重要,但是由于在这种特殊情况下的代码将是无效的两种方式。

+0

问题我得不到,我得到两个单独的行。你的答案是正常的行为。这就是我问这个问题的原因。 – Sabrina

+0

@Sabrina - 什么*“我得到两个单独的行”*是什么意思?你应该从哪里得到它?你写你的代码。 – StoryTeller

+0

@Sabrina - 谢谢你解释你的问题。请参阅我的编辑。 – StoryTeller

0

\后跟一个换行符的C预处理器的行为是从输入中删除两个字节。这是在解析的很早阶段完成的。然而,预处理器保留了它看到的每个令牌的原始行号,并尝试在单独的行上输出令牌,供编译器在后续编译阶段发出正确的诊断信息。

对于输入:

ret\ 
urn 1; 

它可能会产生:

#line 1 "myfile.c" 
return 
#line 2 "myfile.c" 
1; 

它可以缩短为

return 
1; 

注意,您可以在任何位置进行分割任何输入线逃脱的换行符:

#inclu\ 
de <st\ 
dio.h>\ 

"Hello word\\ 
n" 

for (i = 0; i < n; i+\ 
+) 

ret\ 
\ 
\ 
urn; 

\ 
r\ 
et\ 
urn\ 
123;\ 
3

-E输出不是由标准正式规定的。这是在几个不同的设计约束条件,其中符合的两个是工程折衷:

  • 空白必须插入或使“编译适当的”(想象喂养-E输出回gcc -fpreprocessed必要删除 - 这是-save-temps所做的)看到它通常会(不含-E)的相同序列pp-token。 (请参阅C99第6.4节以了解pp令牌的定义。)
  • 尽可能使用令牌应该出现在他们在原始源代码中所做的相同行和列位置,以便错误消息和调试信息尽可能准确。

下面是如何适用于你的例子:

ret\ 
urn 0; 

反斜杠换行结合return成一个单一的PP-令牌,因此它必须出现一起在输出一行。然而,0;应继续保留在其原始行和列中,以便诊断准确无误。所以你得到

return 
    0; 

插入空格,以保持0在其原始列。

ret\ 
    urn 0; 

这里反斜杠换行后面紧跟着空白,所以return已被合并,因此,再次诊断是最准确的,如果一切保持它原来是和输出是

ret 
    urn 0; 

看起来像反斜杠新行没有任何效果。

您可能会发现gcc -E -P的输出不那么令人惊讶。 -P告诉预处理器不要试图保留令牌位置(并关闭输出中以#开头的所有行)。您的示例在-P模式下生成return 0;ret urn 0;,全都在一行上。最后,一个建议的话:每个人都必须阅读你的代码(并且包括六个月后你自己的代码),如果你从未使用将中间的标记拆分为反斜杠 - 换行符,除非是长字符串文字。这是一个遗留的错误,如果它是从头开始设计的,将不会包含在该语言中。