在C Primer(第5版)一书的帮助下,我从C跳到C,作者陈述如下:
程序员经常在调试期间添加print语句 . 此类语句应始终刷新流 . 否则,如果程序崩溃,输出可能会留在缓冲区中,从而导致程序崩溃的错误推断 .
但网上帖子则另有说法;有人说持续刷新缓冲区对程序不利并导致性能问题 .
我的问题:
什么时候应该使用 std::endl ?
std::endl
作者是错的还是我误解了他所说的任何部分?
您能否提供任何需要刷新输出流的真实场景?
附:
从第4点开始,因为其他一切都取决于它和第3点,因为它紧密相关 .
刷新流时,将获取流存储的所有数据并将其写入流所代表的基础介质 .
当它被刷新时,它被完成,提交并准备好被外界观察(或多或少 . 操作系统和支持流的硬件也可能延迟写入,但是你没有太多可以做的事情) . 在刷新之前,您无法读取它 . 如果它从未被刷新,你就无法阅读它 .
问题是你不想经常写入IO,因为任何离开CPU的东西都会花费不计其数的时间 . 有时会慢几万倍 . 在CPU内部,您可以使用千兆赫和并行总线一次移动数据32位或更多位 . 外面你有兆赫经常一次移动一个位 .
将文件作为经典示例 . 驱动器访问不仅以CPU的速度的一小部分运行,而且如果每个字节直接进入磁盘,那么对于每个字节,您可能需要
在磁盘上找到该字节的模拟 .
将该字节周围的扇区加载到内存中 . 因此,不是移动一个字节,而是移动几百或几千 . 通常为512字节或4096字节 .
将字节写入内存中的扇区
将内存中的扇区写回磁盘
野蛮 . 想象一下这样做几百或几千次来写一个字符串 . 但是如果你只是在字符串太大而无法容纳或者你已经完成时写了怎么办?如果你用扇区写而不是字节怎么办?那你可以
在磁盘上找到该字节's analogue' s扇区 .
将存储的扇区写入磁盘
一次性可能数千字节的一次操作 .
第2点可以追溯到第4点/第3点,你无法读取你没有冲洗的内容 . 如果你想在屏幕上看到一个特定的输出,你想现在看到它,你就冲洗了 . 如果你想在程序崩溃之前收到调试消息,并且很可能在没有将最后几条绝对必要的消息放到屏幕上的情况下终止,那么你就会刷新 . 历史上充斥着程序员在错误的位置查找错误,因为他们没有得到最后几个未刷新的错误消息 .
您正在交易程序速度,以确保在需要查看时会看到重要消息 .
点1回调到第2点. std::endl 既是行尾,也是刷新流的指令 . 只有当你需要一个行尾和一个同花顺时,你才会谨慎使用它 . 如果您不需要刷新,只需发送和结束行: '\n' .
'\n'
以Pete Becker的建议为例,尽可能使用 std::cerr 进行错误和调试 . 那是_1851366的痛苦 . 这很慢 . 它几乎总是有效的 .
std::cerr
调试输出应写入 std::cerr ;它的单位是缓冲的,所以每个角色都会被冲洗掉 . 很少需要 std::endl ,养成使用它的习惯会导致代码神秘变慢 . 只要使用 '\n' ,除非您知道需要刷新缓冲区 .
作者和帖子都是对的 .
stream << std::endl 实际上是 stream << '\n' << std::flush . 显式刷新具有性能缺陷,这就是为什么不应该在性能关键的情况下使用它 . 在调试时,您很少考虑这种可忽略的性能问题,因此它实际上是一个明确刷新调试输出的好方法 .
stream << std::endl
stream << '\n' << std::flush
1)什么时候应该使用std :: endl?
当您想确保立即刷新缓冲区时 .
2)是作者错了或我错过了解他所说的任何部分?
不,作者是正确的,你也是 .
3)你能否提供任何真实场景以满足刷新输出流的实际需要?
当在很短的时间内将特定字符串写入流中时,由于每次都不必要地刷新缓冲区,确实可能导致性能损失 . 但是,当涉及为了调试而添加的打印行时,应始终刷新缓冲区 . 再说一遍,如果你首先做错了什么的话 .
默认 std::cout 链接到 stdout ,这是......
std::cout
stdout
当且仅当可以确定流不参考交互设备时,完全缓冲 .
(C99,7.19.3档案,第7段 . )
这意味着,如果您的输出发送到终端, std::endl 与 "\n" 首先没有区别 . ;-)
"\n"
关于你的实际问题:
Both is true:
未刷新的输出缓冲区可能导致对程序崩溃位置的错误推断
刷新输出缓冲区会影响性能
This only becomes a problem once you add "always".
什么时候应该使用std :: endl?
当您想要刷新缓冲区时 .
作者是错的还是我错过了解他所说的任何部分?
我认为就样式/设计/等而言,绝对量词如“永远”,“全部”,“从不”等都应该采取一些盐 .
(例外:从不调用未定义的行为 . ;-))
您能否为实际需要刷新输出流提供任何真实场景?
每当没有实际出现的最新输出是不可接受的 . 在任何给定情况下是否都是这种情况是判断呼叫 .
就个人而言,我会认为 生产环境 /事务日志比调试日志更重要...
你永远不应该使用 std::endl . 这是一种必须消失的货物崇拜 . 给你带来性能上的缺点 . 只要让它成为肌肉记忆:永远 "\n" ,永远 std::endl .
6 回答
第4点和第3点
从第4点开始,因为其他一切都取决于它和第3点,因为它紧密相关 .
刷新流时,将获取流存储的所有数据并将其写入流所代表的基础介质 .
当它被刷新时,它被完成,提交并准备好被外界观察(或多或少 . 操作系统和支持流的硬件也可能延迟写入,但是你没有太多可以做的事情) . 在刷新之前,您无法读取它 . 如果它从未被刷新,你就无法阅读它 .
问题是你不想经常写入IO,因为任何离开CPU的东西都会花费不计其数的时间 . 有时会慢几万倍 . 在CPU内部,您可以使用千兆赫和并行总线一次移动数据32位或更多位 . 外面你有兆赫经常一次移动一个位 .
将文件作为经典示例 . 驱动器访问不仅以CPU的速度的一小部分运行,而且如果每个字节直接进入磁盘,那么对于每个字节,您可能需要
在磁盘上找到该字节的模拟 .
将该字节周围的扇区加载到内存中 . 因此,不是移动一个字节,而是移动几百或几千 . 通常为512字节或4096字节 .
将字节写入内存中的扇区
将内存中的扇区写回磁盘
野蛮 . 想象一下这样做几百或几千次来写一个字符串 . 但是如果你只是在字符串太大而无法容纳或者你已经完成时写了怎么办?如果你用扇区写而不是字节怎么办?那你可以
在磁盘上找到该字节's analogue' s扇区 .
将存储的扇区写入磁盘
一次性可能数千字节的一次操作 .
点2
第2点可以追溯到第4点/第3点,你无法读取你没有冲洗的内容 . 如果你想在屏幕上看到一个特定的输出,你想现在看到它,你就冲洗了 . 如果你想在程序崩溃之前收到调试消息,并且很可能在没有将最后几条绝对必要的消息放到屏幕上的情况下终止,那么你就会刷新 . 历史上充斥着程序员在错误的位置查找错误,因为他们没有得到最后几个未刷新的错误消息 .
您正在交易程序速度,以确保在需要查看时会看到重要消息 .
第1点
点1回调到第2点.
std::endl
既是行尾,也是刷新流的指令 . 只有当你需要一个行尾和一个同花顺时,你才会谨慎使用它 . 如果您不需要刷新,只需发送和结束行:'\n'
.以Pete Becker的建议为例,尽可能使用
std::cerr
进行错误和调试 . 那是_1851366的痛苦 . 这很慢 . 它几乎总是有效的 .调试输出应写入
std::cerr
;它的单位是缓冲的,所以每个角色都会被冲洗掉 . 很少需要std::endl
,养成使用它的习惯会导致代码神秘变慢 . 只要使用'\n'
,除非您知道需要刷新缓冲区 .作者和帖子都是对的 .
stream << std::endl
实际上是stream << '\n' << std::flush
. 显式刷新具有性能缺陷,这就是为什么不应该在性能关键的情况下使用它 . 在调试时,您很少考虑这种可忽略的性能问题,因此它实际上是一个明确刷新调试输出的好方法 .当您想确保立即刷新缓冲区时 .
不,作者是正确的,你也是 .
当在很短的时间内将特定字符串写入流中时,由于每次都不必要地刷新缓冲区,确实可能导致性能损失 . 但是,当涉及为了调试而添加的打印行时,应始终刷新缓冲区 . 再说一遍,如果你首先做错了什么的话 .
默认
std::cout
链接到stdout
,这是......(C99,7.19.3档案,第7段 . )
这意味着,如果您的输出发送到终端,
std::endl
与"\n"
首先没有区别 . ;-)关于你的实际问题:
Both is true:
未刷新的输出缓冲区可能导致对程序崩溃位置的错误推断
刷新输出缓冲区会影响性能
This only becomes a problem once you add "always".
当您想要刷新缓冲区时 .
我认为就样式/设计/等而言,绝对量词如“永远”,“全部”,“从不”等都应该采取一些盐 .
(例外:从不调用未定义的行为 . ;-))
每当没有实际出现的最新输出是不可接受的 . 在任何给定情况下是否都是这种情况是判断呼叫 .
就个人而言,我会认为 生产环境 /事务日志比调试日志更重要...
你永远不应该使用
std::endl
. 这是一种必须消失的货物崇拜 . 给你带来性能上的缺点 . 只要让它成为肌肉记忆:永远"\n"
,永远std::endl
.