【问题标题】:Mixing cout and wcout in same program在同一个程序中混合 cout 和 wcout
【发布时间】:2012-02-15 09:42:28
【问题描述】:

我正在阅读具有以下 sn-p 的“C++ Cookbook”:

// cout  << s  << std::endl;  // You shouldn't be able to
wcout << ws << std::endl;     // run these at the same time

如果您有兴趣查看实际示例,这里是a link to the page on Google books

另外,我发现这个SO question 似乎表明混合 wcout 和 cout 是可以的。有人可以向我解释一下这条评论在说什么吗?

编辑

来自 C++ 标准 [27.4.1]:

在相应的宽字符流和窄字符流上混合操作遵循与在 FILE 上混合此类操作相同的语义,如 ISO C 标准的修订 1 中所述。

来自 C 标准 [7.19.2]:

每个流都有一个方向。在流与外部文件关联之后,但是 在对其执行任何操作之前,流是没有方向的。一旦宽 字符输入/输出功能已应用于无方向的流,该流变成了宽方向的流。同样,一旦一个字节输入/输出函数具有 被应用到一个没有方向的流上,这个流就变成了一个面向字节的流。 只有调用 freopen 函数或 fwide 函数才能改变 流的方向。 (成功调用 freopen 会删除任何方向。)

字节输入/输出函数不应应用于面向宽的流和宽 字符输入/输出函数不应应用于面向字节的流。

所以,标准似乎说你不应该混合它们。但是,我找到了这句话from this article

对于 Visual C++ 10.0,fwide 函数被记录为未实现。从实际的角度来看,至少在输出整行的层面上,混合使用 cout 和 wcout 显然可以正常工作。因此,令人高兴的是,Visual C++ 显然只是无视标准的要求,并且没有保持不切实际的显式 C 文件流方向。

另外,关于 gcc,我从here 找到了这句话:

这是一个(新的)功能,而不是错误,请参阅 libstdc++/11705 和一般搜索 关于 C 标准 (C99, 7.19.2) 中的流方向。简而言之你 不能混合面向字节和面向宽的 I/O。目前,由于 错误 在 libstdc++/11705 中指出,您可以获得接近您的 通过调用 std::ios::sync_with_stdio(false);在。。。之初 你的程序。

【问题讨论】:

    标签: c++


    【解决方案1】:

    当第一次调用coutwcout 时,stdout 的方向变为设置。在cout 的情况下,stdout 成为面向字节的流,在wcout 的情况下,stdout 成为面向宽的流。根据 C++ 标准 [27.4.1] 和 C 标准 [7.19.2],一旦设置了流的方向,就不应调用与该流的方向不兼容的函数。

    【讨论】:

      【解决方案2】:

      我不知道。

      除了线程,您不能“同时”运行任何两条语句。不过,您当然可以在程序的不同位置使用coutwcout。它们都映射到STDOUT,就是这样……尽管在某些情况下,您可能会遇到不同的缓冲区并获得稍微意外的排序。

      显然,每个都在“目标”流STDOUT 上注入了一个方向,并且不允许在已注入方向[C++11: 27.4.1] 和@987654326 的流上混合操作@。

      【讨论】:

      • 我实际上检查了这本书的勘误页,因为我认为它可能是一个错误,但找不到任何东西。
      • @Jesse:是时候联系作者了,也许吧。
      • 您能解释一下您的意思以及实际发生的情况:“它们都映射到 STDOUT”吗? , 谢谢
      • @Mr.Anubis:它们都是将数据发送到宿主环境的“标准输出”终端流的 C++ 流对象,简称STDOUT。我指出,两个流最终都会将您的数据带到同一个地方。
      • 经过一番搜索,标准似乎禁止混合 cout 和 wcout(请参阅我的编辑),但是,一些实现完全允许它。
      【解决方案3】:

      作为猜测:coutwcout 是两个不同的流,您提供的引号没有说明流方向如何与基础文件的方向相关。可能是流在后台默默地重新定向stdout

      【讨论】:

        【解决方案4】:

        违反标准中的“不应”通常会使您陷入未定义行为的领域。未定义的行为可能在某些实现上正常工作。

        【讨论】:

          【解决方案5】:

          从技术上讲,您绝对可以同时使用窄流和宽流。但是,除非您安排它们对字符进行相同的编码,否则结果可能会变得混乱。不幸的是,这伴随着一个警告,即您无法控制标准流对象使用的编码,至少不可移植。即使编码相同,您也需要确保部分字符被完全写入,即至少您需要在切换到其他宽度时刷新缓冲区。

          【讨论】:

          • 标准中没有为流定义imbue,或者我应该如何解释?
          • @Voo imbue() 实际上为所有流对象定义的。但是,使用std::codecvt&lt;...&gt; 所需的唯一流缓冲区是std::basic_filebuf&lt;...&gt;。但是,标准流对象不需要使用这种流缓冲区。他们可能会使用std::basic_filebuf&lt;...&gt;,但我不会指望它,部分原因是我无法想象我会以这种方式实现它。实际上,我应该检查一下 C++2011 标准:在 C++2003 中确实如此,但我认为它没有改变。
          • 这很有趣——我只使用imbue 来处理它工作正常的文件,但我隐含地希望这也适用于标准流对象。很高兴知道 - 但是有一个原因我从一开始就不需要它用于标准流,所以在实践中可能没什么大不了的..
          • @Voo 我似乎记得即使对于文件流,调用imbue() 的效果也会受到限制。特别是,如果已经读取了字符或执行了查找,我认为不需要更改编码。
          • 根据我的发现,你不应该混合它们,但是,一些实现允许它(见我的编辑)。
          猜你喜欢
          • 2011-02-12
          • 2019-09-21
          • 1970-01-01
          • 1970-01-01
          • 2013-09-11
          • 1970-01-01
          • 2015-11-27
          • 1970-01-01
          相关资源
          最近更新 更多