“文件末尾没有换行符”编译器警告


187

在某些C ++编译器中发出以下警告的原因是什么?

文件末尾没有换行符

为什么在源/头文件的末尾应该有一个空行?


17
并不是真正的原因,但是如果您使用的cat是文件且它没有尾随换行符,则很烦人,因为新的Shell提示符将出现在文件的最后一行之后(即不在列0中)
ThiefMaster

由于这个原因,我的$ PS1以换行符开头。(无论如何,这都是多行提示,在一行上包含一堆有用的信息,然后在一行上仅包含提示字符,这样就不会包装相当长的命令)
bames53 2014年

7
Why should I have an empty line at the end of a source/header file-如果文本文件包含one\ntwo\nthree\n三行,则其中三行都不为空。如果一个文本文件包含one\ntwo\nthree一个文本文件,则它不是文本文件,从某种意义上说,结尾没有句号的句子不是句子。
Brandin 2014年

Answers:


217

想想如果没有换行符可能会发生的一些问题。根据ANSI标准#include,文件的开头将完全按照文件的开头插入文件,并且不会#include <foo.h>在文件内容之后插入新行。因此,如果您在解析器的末尾包含一个没有换行符的文件,它将被视为的最后foo.h一行与的第一行位于同一行foo.cpp。如果foo.h的最后一行是注释而没有换行怎么办?现在,第一行已foo.cpp被注释掉。这些只是可能蔓延的问题类型的几个示例。


只是想指出任何有兴趣的人士对下面詹姆斯的回答。尽管以上答案对于C仍然是正确的,但新的C ++标准(C ++ 11)已更改,因此,如果使用C ++和符合C ++ 11的编译器,则不再发出此警告。

从C ++ 11标准通过James的文章:

源文件不为空且不以换行符结尾,或者在任何此类拼接发生之前以反斜杠字符开头的换行符结尾的源文件,应被视为附加的换行符,行字符已附加到文件中(C ++ 11§2.2/ 1)。


28
当然,实际上,每个编译器都会在#include之后添加新行。谢天谢地。
mxcl

3
我记得Microsoft Visual C ++的旧版本(如2.x或类似版本)确实存在此问题。之所以恶化,是因为IDE编辑器鼓励了这种缺少换行符的行为。
格雷格·休吉尔

2
编译器当前可能不会抱怨,但是GitHub实际上会抱怨。
Puyover 2013年

1
我可以看到James“以下”答案,但是:OrderBy中的“以上答案”是什么?!以上是问题,正如我通常以投票方式排序。还是您自己说的答案?
mbx 2014年

@Thomas:该程序是否调用了未定义的行为,因为它没有以换行结尾。在此处查看程序:ideone.com/jswwf9
析构

44

C ++ 11中删除了每个源文件都以不转义的换行符结尾的要求。规范现在显示为:

源文件不为空且不以换行符结尾,或者在任何此类拼接发生之前以反斜杠字符开头的换行符结尾的源文件,应被视为附加的换行符,行字符已附加到文件中(C ++ 11§2.2/ 1)。

合格的编译器不应再发出此警告(如果编译器具有用于语言规范的不同版本的模式,则至少在以C ++ 11模式编译时不应该发出此警告)。


4
对于C ++来说,这一切都很好。不幸的是,即使在即将到来的C1X标准的最新草案中,C仍然说它是UB。
亚当·罗森菲尔德

11
这个问题被标记为[c ++],而不是[c]。
James McNellis 2011年

3
即使这样,它也应该标记为[c],因为许多在C中搜索此警告的人都会在这里找到自己的方式。
亚当·罗森菲尔德

1
这仍然是一个很好的补充。在上面加起来。希望你不要介意。
TJ Seabrooks

25

C ++ 03标准[2.1.1.2]声明:

...如果非空的源文件没有以换行符结尾,或者以任何反斜杠字符开头的换行符结尾(在进行任何此类拼接之前),则行为未定义。


16

“服从”的答案是“因为C ++ 03标准指出未定义以换行符结尾的程序的行为”(解释)。

好奇的答案在这里:http : //gcc.gnu.org/ml/gcc/2001-07/msg01120.html


4
啊,心爱的“不确定行为”。当其他语言失败时,c / c ++会以“未定义”的方式运行:)当然,这是其魅力的很大一部分。而且我不是在开玩笑。
shylent 2010年

6

它不是指空行,而是最后一行(可以包含内容)是否以换行符终止。

大多数文本编辑器会将换行符放在文件最后一行的末尾,因此,如果最后一行没有一行,则存在文件被截断的风险。但是,有充分的理由说明为什么您不希望换行符,所以它只是一个警告,而不是一个错误。


5

#include将其行替换为文件的文字内容。如果文件不以换行符结尾,则包含该文件的行将#include与下一行合并。


2

我正在使用无c IDE版本5.0,在我的程序中,无论是“ c ++”还是“ c”语言,我都遇到了同样的问题。只是在程序的末尾,即程序的最后一行(在花括号后面可能是主要或任何功能),请按Enter键。将增加1.然后执行相同的程序,它将运行无错误。


2

当然,实际上,每个编译器都会在#include之后添加新行。谢天谢地。– @mxcl

不是特定的C / C ++,而是C语言:使用GL_ARB_shading_language_include扩展名时,OS X上的glsl编译器不会警告您缺少换行符。因此,您可以编写一个MyHeader.h带有标头保护符的文件,该文件以结尾,#endif // __MY_HEADER_H__并且您肯定在该行之后丢失该行#include "MyHeader.h"


2

因为如果文件不以换行结尾,则行为在C / C ++版本之间会有所不同。特别讨厌的是较旧的C ++版本,标准说的C ++ 03中的fx(翻译阶段):

如果不为空的源文件没有以换行符结尾或以反斜杠字符开头的换行符结尾,则该行为是未定义的。

未定义的行为是不好的:符合标准的编译器可能在这里或多或少地执行其想要的操作(插入恶意代码或其他内容),这显然是发出警告的原因。

尽管在C ++ 11中情况较好,但最好避免在早期版本中未定义行为的情况。C ++ 03规范比C99差,后者完全禁止此类文件(然后定义行为)。


我怀疑标准表示没有尾随换行符的程序具有未定义的行为,而不是说它们格式错误,因为某些编译器会将包含文件的未终止的最后一行与#include指令后面的源代码文本连接起来,并且某些针对此类编译器的程序员可能已经利用了此类行为。使标准使此类事物保持未定义状态将使利用此类怪癖的程序在指定此类行为的平台上得到良好定义。具有标准强制性的行为会破坏此类程序。
2015年

0

此警告还可能有助于指示文件可能已被截断。确实,无论如何编译器都可能会抛出编译器错误-尤其是在函数中间-或链接器错误,但是这些错误可能更隐蔽,并且不能保证会发生。

当然,如果在换行符后立即截断文件,也不能保证此警告,但是它仍然可以捕获某些可能遗漏其他错误的情况,并为问题提供更强的提示。


-2

那不是错误。这只是一个警告。

在编辑器中打开文件,转到文件的最后一行,然后按Enter键以在文件末尾添加空白行。

不过,除此之外,您应该使用#include <iostream>而不是<iostream.h>。然后放在using std::cout;后面。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.