是否需要在 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 页:

您必须使用\nprintf 参数中包含换行符;如果你尝试类似

 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 字符,而且我从未见过编译器抱怨缺少\nprintf

这里有一个问题,但不是编译时错误。

一些例子:

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 &lt; 100000; i++ ) printf( "%d ", i ); sleep( 10 ); --- 在我的系统上,它在打印 99984 后停止...

以上是关于是否需要在 C 中将'\n' 提供给 printf()?的主要内容,如果未能解决你的问题,请参考以下文章

如何在我的 C 代码中将字符串返回给操作系统?

如何在 C 中将 linux syslog 映射到 printf

如何在-ggwin中将-pg传递给gcc

如何在 C 中将字节数组转换为十六进制字符串?

C语言中将字符串打印成指定长度的方法

在C中将奇数索引元素从一个数组复制到另一个数组