关于printf输出的误区

纹枰老妖 2014-08-07 08:59:30
我在一本书上看过这样一段介绍: 电脑屏幕应该在什么时候显示printf里的内容呢?有三点—— 1、输出缓冲区存满的时候。 2、遇到换行符 \n 的时候。 3、遇到其它输入性质的动作,比如遇到scanf函数的时候。

为了试验一下,我做了如下的代码:[code=c#include "stdio.h"
void main()
{
int i;
printf("现在刷新了吗?");
for(i=0;i<1000000000;i++);
printf("\n结束");
}][/code]

问题是,我的程序执行后,会立马显示 “现在刷新了吗?” 这句话,而不是如我预想的,等到执行完for循环体【大概需要两秒执行完毕】才跟 ”\n结束“ 一起显示在屏幕上。
这是为什么.?前面说的那三个条件一个都没满足啊,既没有存满输出缓冲区,也没有遇到换行符,更没有遭遇输入动作。请知情人解惑!
...全文
271 14 打赏 收藏 转发到动态 举报
写回复
用AI写文章
14 条回复
切换为时间正序
请发表友善的回复…
发表回复
赵4老师 2014-08-13
  • 打赏
  • 举报
回复
引用 7 楼 wenpinglaoyao 的回复:
怎么跟踪查看printf??
VC调试时按Alt+8、Alt+7、Alt+6和Alt+5,打开汇编窗口、堆栈窗口、内存窗口和寄存器窗口看每句C对应的汇编、单步执行并观察相应堆栈、内存和寄存器变化,这样过一遍不就啥都明白了吗。
辰岡墨竹 2014-08-09
  • 打赏
  • 举报
回复
引用 12 楼 taodm 的回复:
换本好书,生命可贵。
那本书是相当权威书。C99规定: At program start-up, three text streams are predefined and need not be opened explicitly - standard input (for reading conventional input), standard output (for writing conventional output), and standard error (for writing diagnostic output). As initially opened, the standard error stream is not fully buffered; the standard input and standard output streams are fully buffered if and only if the stream can be determined not to refer to an interactive device. 所以当标准输出被重定向到文件的话,是完全缓冲的。链接到终端的话,不是完全缓冲的。 但是,标准并没有规定是到底是那种模式,那是由实现定义的行为。 对于UNIX/Linux,终端是默认行缓冲的,这个是有历史原因的,和TTY(电传打字机)模式有关,当初那种主机-终端机的模式,如果每次打印一个字符或输入一个字符都要调用一次通信实在太慢了,所以标准输入输出都是行缓冲的。 而Windows的C库则是兼容的DOS里Microsoft C的行为,从MSDN里对于setvbuf的说明来看: _IOLBF For some systems, this provides line buffering. However, for Win32, the behavior is the same as _IOFBF - Full Buffering .微软的CRT库不支持行缓冲模式(等同于完全缓冲),所以连接到终端的stdout"应该"是无缓冲的。 注意是应该,有趣的是从这篇知识库文章可知 http://support.microsoft.com/kb/44725/en-us 第一次调用printf时,16位应用程序会分配512字节标准I/O缓冲区,32位应用程序会分配4096字节。所以很奇怪,我有点儿怀疑那个”标准I/O缓冲区“是不是setvbuf里指的标准里的stdin、stdout缓冲区。 哪位有兴趣的,可以帮我测试一下在XP和Win7中,以及使用不同的MS编译器(早期的VS6.0,以及微软开始遵守C规范的2008、2010),那个程序的行为是否一致。也许默认缓冲行为会不一样。
赵4老师 2014-08-08
  • 打赏
  • 举报
回复
为什么不跟踪或查看printf的源代码呢? 参考C:\Program Files\Microsoft Visual Studio\VC98\CRT\SRC\OUTPUT.C
taodm 2014-08-08
  • 打赏
  • 举报
回复
换本好书,生命可贵。
AndyStevens 2014-08-08
  • 打赏
  • 举报
回复
跟编译器相关吧
KangRoger 2014-08-08
  • 打赏
  • 举报
回复
这个应该和系统有关。标准输出的确是行缓冲的。 刚刚跑了一下楼主的程序,在windows下的编译器C-Free中,printf("现在刷新了吗?")立刻输出。 在Linux下gcc编译,for循环后输出。
KangRoger 2014-08-08
  • 打赏
  • 举报
回复
引用 10 楼 lin5161678 的回复:
[quote=引用 3 楼 KangRoger 的回复:] 这个应该和系统有关。标准输出的确是行缓冲的。 刚刚跑了一下楼主的程序,在windows下的编译器C-Free中,printf("现在刷新了吗?")立刻输出。 在Linux下gcc编译,for循环后输出。
标准哪里说标准输出是行缓冲了 ? [/quote] 我在Unix高级环境编程看到的,并没有实际项目经验得出这个结论。5.4缓冲那一结有讲到。
lin5161678 2014-08-08
  • 打赏
  • 举报
回复
引用 3 楼 KangRoger 的回复:
这个应该和系统有关。标准输出的确是行缓冲的。 刚刚跑了一下楼主的程序,在windows下的编译器C-Free中,printf("现在刷新了吗?")立刻输出。 在Linux下gcc编译,for循环后输出。
标准哪里说标准输出是行缓冲了 ? 
Falleyes 2014-08-08
  • 打赏
  • 举报
回复
测试如下代码:
#include "stdio.h"
int main()
{
	int i;
	printf("现在刷新了吗?");
	for (i = 0; i<1000000000; i++);
	printf("现在刷新了吗?");
	for (i = 0; i<1000000000; i++);
	printf("结束");
}
你会看到,并不是遇到'\n'才输出到屏幕的。
mujiok2003 2014-08-08
  • 打赏
  • 举报
回复
引用
电脑屏幕应该在什么时候显示printf里的内容呢?有三点—— 1、输出缓冲区存满的时候。 2、遇到换行符 \n 的时候。 3、遇到其它输入性质的动作,比如遇到scanf函数的时候。
再加一点, stdcout没有被重定向。
引用
The default streams stdin and stdout are fully buffered by default if they are known to not refer to an interactive device. Otherwise, they may either be line buffered or unbuffered by default, depending on the system and library implementation. The same is true for stderr, which is always either line buffered or unbuffered by default.
参考以上内容。
lin5161678 2014-08-08
  • 打赏
  • 举报
回复
引用
前面说的那三个条件一个都没满足啊
你怎么确定不满足 ? 比如缓冲区满的那个条件 你怎么知道你的缓冲区有多大 万一你的缓冲区是 0 那么你printf 字符进去不就都触发了这个缓冲区满的条件了么
纹枰老妖 2014-08-08
  • 打赏
  • 举报
回复
怎么跟踪查看printf??
纹枰老妖 2014-08-08
  • 打赏
  • 举报
回复
但那个换行符是在for循环后面啊,也就是for循环还没执行完之前不应该显示在屏幕上啊
勤奋的小游侠 2014-08-07
  • 打赏
  • 举报
回复
2、遇到换行符 \n 的时候 你这里面不是输出了一个换行了吗?既然遇到 了\n,上一个printf当然要马上输出了。 printf("\n结束"); 何况 1、输出缓冲区存满的时候。 你怎么确定你的缓冲区多大?你测试过了吗?你怎么知道一条printf就不能充满?
第1篇 理解程序设计 第1章 基础知识 1.1 什么是编程 1.1.1 计算机如何工作 1.1.2 内存中的程序是哪里来的 1.1.3 可执行文件的制作 1.1.4 C语言的演化 1.2 怎样用C语言编程 1.2.1 学习C语言编程都需要什么 1.2.2 最简单的C语言程序的基本结构 1.2.3 Dev C++ 1.3 printf()函数初步 1.3.1 简单的一般用法 1.3.2 特殊的字符 1.4 C语言的“字母”和“单词” 1.4.1 C语言的字母 1.4 12C语言的“词” 小结 概念与术语 风格与习惯 常见错误 牛角尖 练习与自测 第2章 数据类型 2.1 什么是数据类型 2.1.1 “三个世界”理论 2.1.2 问题世界:“万物皆数” 2.1.3 代码世界:书写规则及含义 2.1.4 机器世界里的“机器数” 2.1.5 输出问题 2.1.6 计算2的1到10次幂 2.1.7 代码质量的改进 2.2 让程序记住计算结果——变量 2.2.1 计算机的记忆功能 2.2.2 在代码中实现“记忆 2.3 int类型——总结与补充 2.3.1 计算机表示负整数的几种方法 2.3.2 计算机码制和C语言的关系 2.3.3 暂时不必关心的一些细节 2.3.4 int类型值的范围 2.3.5 int类型常量在代码中的其他写法 2.3.6 Dev C++中int类型的机器数 2.4 对数据类型的进一步讨论 2.4.1 int数据类型的运算 2.4.2 数学公式与数据类型 2.4.3 数据类型——代码与编译器的约定 2.5 莫名其妙的“整型 2.5.1 unsignedint类型 2.5.2 long、short关键字描述的整数类型 2.5.3 没有常量的char类型 2.5.4 其他 2.6 浮点类型 2.6.1 double类型常量的代码书写规则 2.6.2 浮点类型数据存储模型 2.6.3 浮点类型的一些特性 2.6.4 浮点类型的运算 2.6.5 浮点类型的输出及其他 2.7 数据类型与算法 2.7.1 错误的数据类型 217.2 所谓算法 2.7.3 一个技巧 2.7.4 更高效率的写法 2.8 算法的特性 小结 概念与术语 风格与习惯 常见错误 牛角尖 练习与自测 第3章 运算符、表达式及语句 3.1 C的“动词”及“动词”的“宾语” 3.2 表达式——C语言的“词组 3.2.1 初等表达式 3.2.2 被误解的“() 3.2.3 带运算符的表达式 3.2.4 不像表达式的表达式 3.2.5 表达式:专业与副业 3.2.6 赋值运算符左侧的标识符称为左值 3.2.7 函数调用是表达式不是语句 3.3 谁是谁的谁 3.3.1 流行的谬误:优先级决定运算次序 3.3.2 “左结合性”是运算对象先与左面的运算符相结合吗 3.3.3 运算符、表达式小结 3.4 右值的类型转换 3.4.1 明确写出的显式转换——cast运算 3.4.2 cast运算的规则 3.4.3 赋值中的转换 3.4.4 1+1.0=? 3.4.5 算术转换:早已废弃的规则和依然有效的规则 3.5 语句的概念 3.5.1 关于语句的闲话 3.5.2 空语句有两种 3.5.3 表达式语句 3.5.4 顺序结构 3.5.5 复合语句 3.6 例题 3.6.1 简单的类型转换 3.6.2 最基础的算法——交换变量的值 3.6.3 编程不是列公式 3.7 算法和数据结构初窥 3.8 在程序运行时提供数据 小结 概念与术语 风格与习惯 常见错误 牛角尖 练习与自测 第4章 选择语句 4.1 关系运算 4.1.1 “<”的数学含义及代码含义 4.1.2 4种关系运算符 4.1.3 常见误区及与常识不符的结果 4.2 if语句 4.2.1 语法格式及含义 4.2.2 例题 4.2.3 ()内的表达式 4.2.4 ()后面的语句 4.3 判等运算 4.4 表达复杂的条件 4.5 if else语句 4.6 鸡肋——Bool类型(C99) 4.7 判断三角形种类 4.8 显得很有学问的运算符 4.9 大师如是说goto 4.10 给程序更多选项——Switch语句 4.10.1 switch语句的一种应用形式 4.10.2 switch语句中的break语句 4.11 程序开发的过程 小结 概念与术语 风格与习惯 常见错误 牛角尖 练习与自测 第5章 从循环到穷举 5.1 造句:当就 5.1.1 语法要素 5.1.2 猴子吃桃问题更简洁的写法 …… 第2篇 结构化程序设计与简单的数据结构 第6章 最复杂的去处符——“()” 第7章 作为类型说明符和去处符的“[]” 第8章 结构体、共用体与位运算 第9章 指针 第10章 字符串、字符数组及指向字符的指针 第3篇 复杂的数据结构、算法及其他话题 第11章 复杂的数据类型与算法 第12章 程序的输入与输出 第13章 程序组织与编译预处理 第14章 标准库简介 附录 参考文献

33,311

社区成员

发帖
与我相关
我的任务
社区描述
C/C++ 新手乐园
社区管理员
  • 新手乐园社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧