某些编译器(尤其是 C 或 C++ 编译器)会向您发出以下警告:
No new line at end of file
我认为这只是 C 程序员的问题,但 github 在提交视图中显示一条消息:
\ No newline at end of file
对于 PHP 文件。
我理解预处理器的解释这个线程,但这和 PHP 有什么关系呢?是同一件事还是与vs主题include()
相关?\r\n
\n
在文件末尾添加新行有什么意义?
答案1
这不是在文件末尾添加额外的换行符,而是不删除应该存在的换行符。
A文本文件在unix下,由一系列线,每个都以换行符( \n
)。因此,非空且不以换行符结尾的文件不是文本文件。
应该对文本文件进行操作的实用程序可能无法很好地处理不以换行符结尾的文件;例如,历史 Unix 实用程序可能会忽略最后一个换行符之后的文本。GNU实用程序有一个对非文本文件表现良好的策略,大多数其他现代实用程序也是如此,但您仍然可能会遇到缺少最后换行符的文件的奇怪行为。
使用 GNU diff,如果被比较的一个文件以换行符结尾,而另一个文件则不然,则要小心地注意这一事实。由于 diff 是面向行的,因此它无法通过为其中一个文件存储换行符来指示这一点,但不能为其他文件存储换行符 - 换行符必须指示每一行的位置在差异文件中开始和结束。因此 diff 使用此特殊文本\ No newline at end of file
来区分未以换行符结尾的文件和以换行符结尾的文件。
顺便说一句,在 C 上下文中,源文件同样由一系列行组成。更准确地说,翻译单元在实现中被视为定义为一系列行,每行必须以换行符结尾(n1256§5.1.1.1)。在 UNIX 系统上,映射很简单。在 DOS 和 Windows 上,每个 CR LF 序列 ( \r\n
) 都映射到换行符(\n
这是在这些操作系统上读取作为文本打开的文件时总是发生的情况)。有一些操作系统没有换行符,而是具有固定或可变大小的记录;在这些系统上,从文件到 C 源代码的映射\n
在每个记录的末尾引入 。虽然这与 unix 没有直接关系,但它确实意味着,如果您将缺少最终换行符的 C 源文件复制到具有基于记录的文本文件的系统,然后将其复制回来,您将得到不完整的结果最后一行在初始转换中被截断,或者在反向转换期间添加了额外的换行符。
1
示例:GNU 在非空文件上的输出sort
始终以换行符结尾。因此,如果文件foo
缺少最后的换行符,您会发现sort foo | wc -c
报告比cat foo | wc -c
.需要返回内置read
的sh
错误的如果在到达行尾之前到达文件末尾,那么您会发现诸如while IFS= read -r line; do ...; done
完全跳过未终止行之类的循环。
答案2
不一定是原因,而是文件不以新行结尾的实际后果:
考虑一下如果您想使用cat
.例如,如果您想foo
在 3 个文件中查找行开头的单词:
cat file1 file2 file3 | grep -e '^foo'
如果 file3 中的第一行以 开头foo
,但 file2 在其最后一行之后没有结尾\n
,则 grep 不会找到这种情况,因为 grep 将 file2 中的最后一行和 file3 中的第一行视为单个线。
因此,为了保持一致性并避免意外,我尝试让我的文件始终以新行结尾。
答案3
有两个方面:
如果最后一行不以换行符结尾,有些 C 编译器无法解析它。 C 标准指定 C 文件应以换行符结尾(C11、5.1.1.2、2.),并且没有换行符的最后一行会产生未定义的行为(C11、J.2、第 2 项)。也许是出于历史原因,因为在编写第一个标准时,此类编译器的某些供应商是委员会的成员。因此,海湾合作委员会发出了警告。
diff
程序(如 、github 等使用的git diff
)逐行显示文件之间的差异。当只有一个文件以换行符结尾时,他们通常会打印一条消息,否则您将看不到这种差异。例如,如果两个文件之间的唯一区别是最后一个换行符的存在,如果没有提示,则两个文件看起来是相同的,当diff
和cmp
返回退出代码不相等的成功和文件的校验和(例如通过md5sum
) 不匹配。
答案4
保留 diff 历史记录也很重要。如果文件结尾没有换行符,则在文件末尾添加任何内容都将被 diff 实用程序视为更改最后一行(因为\n
正在添加到其中)。
git blame
这可能会导致和等命令产生不需要的结果hg annotate
。