cstdio 流与 iostream 流?

2022-01-07 00:00:00 c stream iostream c++ cstdio

我刚刚了解到ios_base::sync_with_stdio 函数的存在,它基本上允许您关闭(如果您已经关闭它,则打开)iostream 之间的同步code> 在 C++ 中使用的流和作为标准 C 的一部分的 cstdio 流.

I just learned of the existence of the ios_base::sync_with_stdio function, which basically allows you to turn off (or on if you already turned it off) the synchronization between iostream streams that are used in C++ and the cstdio streams that are part of Standard C.

现在,我一直认为 C 中的 stdoutstderrstdin 在 iostreams 中本质上被包裹在 C++ 中的一组对象中类.但是,如果它们必须同步彼此,这将表明 C++ 的 iostream 类不是 C 的 stdin<的包装器/code> 等

Now, I always thought that stdout, stderr and stdin in C were essentially wrapped in a set of objects in C++ in the iostreams classes. But if they have to be synchronized with each other, this would indicate that C++'s iostream classes are not a wrapper around C's stdin etc.

我对此很困惑?有人可以澄清 C++ 的 iostream 和 C 的 stdio 是如何不同 做完全相同的事情,只是在不同的抽象级别?我以为它们是同一件事!?

I'm quite confused by this? Can someone clarify how C++'s iostream and C's stdio are different things that do exactly the same thing, just at a different level of abstraction? I thought they were the same thing!?

它们是如何同步的?我一直认为它们是一回事,本质上是一个包裹另一个.

How it is that they have to be synchronized? I always thought they were the same thing, one wrapping the other, essentially.

推荐答案

C 和 C++ 标准对事物的实现方式没有要求,只对某些操作的效果有什么要求.对于 <stdio><iostream> 功能,这意味着一个可以包装另一个,两者可以本质上相同,或者它们要么完全独立.从技术上讲,出于多种原因,使用通用实现将是理想的(例如,不需要显式同步,并且会有一个定义的机制来为用户定义的系统扩展 FILE*),但我不是意识到任何实际执行此操作的系统.让一个实现成为另一个实现的包装器是可能的,并且根据 实现 是一种典型的实现选择,尽管它有以下缺点它为某些操作带来了额外的成本,并且大多数 C++ 标准库已经转向使用完全独立的实现.

The C and C++ standards make no requirements on how things are implemented, just on what the effect of certain operations is. For the <stdio> vs. <iostream> functionality this means that one could wrap the other, both could be essentially the same, or that they are either entirely independent. Technically, using a common implementation would be ideal for several reasons (e.g. there would be no need for explicit synchronization and there would be a defined mechanism to extend FILE* for user defined systems) but I'm not aware of any system which actually does this. Having one implementation be a wrapper of the other is possible and implementing <iostream>s in terms of <stdio> was a typical implementation choice although it has the drawback that it introduces an extra cost for certain operations and most C++ standard libraries have moved on to use entirely separate implementations.

不幸的是,包装的和独立的实现都有一个共同的问题:在一个字符级别完成时,I/O 的效率低得可怕.因此,缓冲字符和读取或写入缓冲区本质上是强制性的.这对于相互独立的流非常有效.捕获的是标准 C 流 stdinstdoutstderr 和它们的 C++ 窄字符对应物 std::cinstd::coutstd::cerr/std::clog 和 C++ 宽字符对应物 std::wcinstd::wcoutstd::wcerr/std::wclog,分别:当用户从 stdinstd::cin?如果这些流中的任何一个从底层操作系统流读取字符缓冲区,则读取将出现乱序.类似地,如果 stdoutstd::cout 都使用了独立的缓冲区,当用户将两者都写入两个流时,字符将以意外的顺序出现.因此,对标准 C++ 流对象(即 std::cinstd::coutstd::cerr> 和 std::clog 及其对应的宽字符),它们要求它们与各自的 对应物同步.实际上,这意味着这些 C++ 对象要么直接使用通用实现,要么按照 <stdio> 和 实现,并且不缓冲任何字符.

Unfortunately, both the wrapped and the independent implementation share a common problem: I/O is hideously inefficient when done one character level. Thus, it is essentially mandatory to buffer characters and read from or write to a buffer. This works nicely for streams which are independent of each other. The catch are the standard C streams stdin, stdout, stderr and their C++ narrow character counterparts std::cin, std::cout, std::cerr/std::clog and C++ wide character counterparts std::wcin, std::wcout, std::wcerr/std::wclog, respectively: what happens when a user reads both from stdin and std::cin? If either of these stream read a buffer of characters from the underlying OS stream the reads would appear out of order. Similarly, if both stdout and std::cout used independent buffers characters would appear in unexpected order when a user writes both to both streams. As a result, there are special rules on the standard C++ stream objects (i.e. std::cin, std::cout, std::cerr, and std::clog and their wide character counterparts) which mandate that they synchronize with their respective <stdio> counterpart. Effectively, this means that specifically these C++ objects either use a common implementation directly or that they are implemented in terms of <stdio> and don't buffer any characters.

人们意识到,如果实现不共享公共基础并且对于某些用户来说可能是不必要的,则这种同步的成本是相当可观的:如果用户只使用 他不想支付额外的间接费用,更重要的是,他不想支付因不使用缓冲区而产生的额外成本.对于谨慎的实现,不使用缓冲区的成本可能相当可观,因为这意味着某些操作最终必须在每次迭代中进行检查和可能的虚函数调用,而不是偶尔进行一次.因此,std::sync_with_stdio() 可用于关闭此同步,这可能意味着标准流对象或多或少完全改变了它们的内部实现.由于标准流对象的流缓冲区可以被用户替换,不幸的是,流缓冲区不能被替换,但是流缓冲区的内部实现可以改变.

It was realized that the cost of this synchronization is quite substantial if the implementations don't share a common base and may be unnecessary for some users: if a user only uses <iostream> he doesn't want to pay for the extra indirection and, more importantly, he doesn't want to pay for the extra costs imposed by not using a buffer. For careful implementations the cost of not using a buffer can be quite substantial because it means that certain operations end up having to do a check and possibly a virtual function call in each iteration rather than only once in a while. Thus, std::sync_with_stdio() can be used to turn this synchronization off which may mean that the standard stream objects change their internal implementation more or less entirely. Since the stream buffers of the standard stream objects can be replaced by a user, unfortunately, the stream buffers can't be replaced but the internal implementation of the stream buffer can be changed.

库的良好实现中,所有这些只影响标准流对象.也就是说,文件流应该完全不受此影响.但是,如果您想使用标准流对象并希望获得良好的性能,您显然不想将 <stdio><iostream> 和您混合使用想关闭同步.特别是,在比较 之间的 I/O 性能时,您应该注意这一点.

In good implementations of the <iostream> library all this only affects the standard stream objects. That is, file streams should be entirely unaffected by this. However, if you want to use the standard stream objects and want to achieve good performance you clearly don't want to mix <stdio> and <iostream> and you want to turn synchronization off. Especially, when comparing I/O performance between <stdio> and <iostream> you should be aware of this.

相关文章