是否需要在 C 中将'\n' 提供给 printf()?
Posted
技术标签:
【中文标题】是否需要在 C 中将\'\\n\' 提供给 printf()?【英文标题】:Is '\n' necessary to be given to printf() in C?是否需要在 C 中将'\n' 提供给 printf()? 【发布时间】:2014-12-03 16:43:04 【问题描述】:我正在阅读 Brian Kernighan 和 Dennis Ritchie 的《The C Programming Language》一书(第 2 版,由 PHI 出版)。在第一章A Tutorial Introduction第7页的第一篇文章1.1 Getting started中,他们说必须在printf()参数中使用\n
,否则C 编译将产生错误消息。但是当我在 printf() 中编译没有\n
的程序时,它运行良好。我没有看到任何错误消息。我正在使用带有“MinGW GCC 4.6.2 32 位”编译器的 Dev-C 便携版。
为什么我没有收到错误消息?
【问题讨论】:
K&R 现在已经过时了。 @ratchetfreak 如果我使用一些旧的编译器,我可以重现错误吗?这本书可能已经过时了,但我觉得它很有帮助。 @user31782 为什么要使用旧的编译器?放手……继续前进。 我在我的 K&R 中没有看到任何关于此类编译错误的信息。他们说您需要在行尾使用\n
才能通过换行符完成输出。他们还说,如果您尝试在多行上定义字符串,则会出现语法错误。 IE。你不能用左引号、几行文本然后右引号来定义一个字符串。
@user31782:我想你误解了这本书的意思。检查我的答案,如果还不清楚,请告诉我。
【参考方案1】:
这是有问题的段落,来自 K&R 第二版的第 7 页:
您必须使用
\n
在printf
参数中包含换行符;如果你尝试类似printf("hello, world ");
C 编译器会产生错误信息。
这意味着您不能在带引号的字符串中嵌入文字换行符。
但是,以下任何一条都可以:
printf("hello, world"); /* does not print a newline */
printf("hello, world\n"); /* prints a newline */
上面的所有文字都在说,你不能在源代码中包含跨越多行的带引号的字符串。
您还可以使用反斜杠转义换行符。 C 预处理器会去掉反斜杠和换行符,所以下面两条语句是等价的:
printf("hello, world\
");
printf("hello, world");
如果你有很多文本,你可以将多个带引号的字符串并排放置,或者用空格分隔,编译器会为你加入它们:
printf("hello, world\n"
"this is a second line of text\n"
"but you still need to include backslash-n to break each line\n");
【讨论】:
您可以将文字字符串拆分为多行。区分源和输出。见***.com/questions/797318/… 是的,现在我收到了错误消息。我误解了。谢谢你的解释。 @yellowantphil 是否还有其他一些面向 SE 初学者的编程网站,允许所有类型的编程问题。 @user31782 我不这么认为,但我并不完全清楚哪些问题属于哪里。我不知道为什么这个问题被否决了。\n
作为缓冲区被刷新的保证也很重要,即。任何东西都可以打印。要么手动调用fflush(stdout);
。【参考方案2】:
您没有收到编译时错误消息,因为没有错误。
在第一篇文章中他们说必须在
printf()
参数中使用\n
,否则C 编译器会产生错误消息。
您能否(按章节和/或页码)引用该声明出现的位置?我真的不相信 K&R(您使用的是第二版,对吗?)这么说。如果真的这么说,那就是书上的错误了。
更新:本书所说的非常正确的是,字符串文字中的换行符由两个字符序列\n
表示,而不是由实际的换行符表示。字符串文字必须在单个逻辑源代码行上;像
printf("hello
world");
是语法错误。这适用于所有字符串文字,无论它们是否为 printf
格式字符串。
字符串文字中的实际换行符是错误的。 表示换行符的\n
序列是可选的;它的缺失不是错误,但printf
格式字符串应该通常以\n
结尾。
printf
调用不需要包含\n
字符,而且我从未见过编译器抱怨缺少\n
的printf
。
这里有一个问题,但不是编译时错误。
一些例子:
printf("No newline");
这是一个完全合法的电话。它在标准输出上打印指定的字符串,不带换行符。
printf("hello%c", '\n');
格式字符串中没有\n
,但它打印hello
,后跟换行符。同样,这是完全合法的。
实际的问题是您应该(几乎)总是在输出的最后打印一个换行符。这个完整的程序:
#include <stdio.h>
int main(void)
printf("hello");
return 0;
是合法的,但它的行为可能在某些实现中是未定义的。相关规则在标准中,第 7.21.2 节第 2 段(引用来自N1570 draft):
文本流是由字符组成的有序序列 行,每行由零个或多个字符加上一个 终止换行符。最后一行是否需要 终止换行符是实现定义的。
无论是否需要终止换行符,(几乎总是)用换行符结束输出是一个非常好的主意。如果我在我的系统上运行它,我会在同一行立即得到字符串hello
,然后是我的 shell 提示符。这并不违法,但不方便且丑陋。
但这仅适用于程序输出的最后。该程序完全有效并且具有明确定义的行为:
#include <stdio.h>
int main(void)
printf("hello");
putchar('\n');
return 0;
不过,产生干净输出的最简单和最可靠的方法是每次调用 printf
只打印一行,该行恰好以一个 '\n'
字符结尾。这不是一个普遍的规则。有时一次打印一行很方便,或者在单个printf
中打印两行或多行。
【讨论】:
我从来没有遇到过这种事情:printf("Some of Line 1"); printf(". More of Line 1\nLine 2\n");
@WeatherVane - stdout
在您第二次调用 printf
时被刷新,其中包含换行符。在答案中的示例中,只有一个printf
调用,并且换行符永远不会发送到stdout
。如果您使用答案中的示例,您可能看不到您的输出。
@WeatherVane:我不希望你有任何麻烦。你认为我的回答暗示你会吗?
我认为 user31782 是在询问第 7 页底部的文字,就在本章介绍 \n
序列之后。它说您必须使用\n
来获取换行符,而不是在带引号的字符串中按回车键。
@Keith Thompson 我同意你的看法。缺少换行符不是问题,特别是如果一个整洁的程序确保在退出之前有一个。【参考方案3】:
很多时候,如果你没有以\n
结束你的printf
格式字符串,一些输出会保留在stdout
buffer,你需要调用fflush
来获取所有的输出显示。
这意味着如果你没有得到所有预期的输出,你应该在适当的地方添加fflush
(例如在调用fork
之前)。
但在这种情况下您不会收到编译器消息,因为这不是错误(它可能是许多初学者正在做的错误)。如果您真的想要,您可以自定义您的编译器(例如,如果使用最近的 GCC 编译器,则使用 MELT)来获得警告。我认为这不值得付出努力(因为有合法调用printf
而没有任何\n
....)
合法的printf
调用 换行的一个例子是如果你编写一个(递归)函数来从它的AST 输出一个表达式;您当然应该不在每个标记之后发出换行符。
请参阅printf(3)、fflush(3)、stdio(3)、setvbuf(3) 等的文档...
【讨论】:
我得到了所有的输出。保持什么样的输出?我是编程新手,我不知道如何自定义编译器。你能给我看一个编译器应该显示的错误截图吗? @user31782 你不会注意到缓冲,除非你的程序打印了很多输出。然后,您有时不会立即在终端中看到您打印的内容。 @user31782: 不,我相信期望编译器在没有\n
的情况下对printf
进行诊断是不现实的
@user31782 如果您的程序只打印一行然后终止,它可能会刷新缓冲区(即打印该行),但是如果您有很多打印和/或您的程序运行时间很长-time,省略\n
通常会导致您的输出保留在缓冲区中。您可以打印\n
字符,或手动调用fflush(stdout);
来刷新缓冲区并打印您的文本。
@user31782 在您的示例代码中,在您的printf
循环之后放置一个sleep(10);
,您会注意到它可能会打印到某个点,然后停止(即使它在printf
之外循环,在睡眠完成后),其余部分可能会打印。那就是正在刷新的标准输出缓冲区。类似于:main() int i; for ( i = 0; i < 100000; i++ ) printf( "%d ", i ); sleep( 10 );
--- 在我的系统上,它在打印 99984 后停止...以上是关于是否需要在 C 中将'\n' 提供给 printf()?的主要内容,如果未能解决你的问题,请参考以下文章