我知道你不应该把printf,cout和wprintf,wcout混合在一起打印,但是很难找到一个好的答案,为什么以及是否有可能绕过它。问题是我使用了一个外部库,它可以用printf打印,而我自己使用的是wcout。如果我做一个简单的例子,它可以正常工作,但是从我的整个应用程序来看,它根本不打印printf语句。如果这真的是一个限制,那么就会有很多图书馆不能与广泛的打印应用程序一起工作。任何对此的见解都是非常受欢迎的。
更新:
我把它归结为:
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <readline/readline.h>
#include <readline/history.h>
int main()
{
char *buf;
std::wcout << std::endl; /* ADDING THIS LINE MAKES PRINTF VANISH!!! */
rl_bind_key('\t',rl_abort);//disable auto-complete
while((buf = readline("my-command : "))!=NULL)
{
if (strcmp(buf,"quit")==0)
break;
std::wcout<<buf<< std::endl;
if (buf[0]!=0)
add_history(buf);
}
free(buf);
return 0;
}
所以我想可能是冲水的问题,但我还是觉得很奇怪,我得检查一下。
更新-〉解决方法:
首先,wprintf也会出现同样的问题,但是我发现添加:
std::ios::sync_with_stdio(false);
我真的做到了......(注意错误,不是我所期望的那样正确......),唯一困扰我的是,我不明白为什么和如何弄清楚:-(
6条答案
按热度按时间jckbn6z71#
我想你说的是
std::ios_base::sync_with_stdio
,但IIRC默认情况下是打开的。bq9c1y662#
您应该能够混合它们,但它们通常使用单独的缓冲机制,因此它们彼此重叠:
可能导致:
你好,这是一个令人惊奇世界
你没有提供足够的信息来诊断你的应用程序中printf()的问题,但是我怀疑你有不止一个c运行时(一个在你的代码中,一个在printf()代码中),并且存在冲突。
camsedfj3#
printf()和cout缓冲区默认是同步的,或者实际上是同一个缓冲区,如果缓冲区有问题,显而易见的解决方案是在每次输出后刷新缓冲区:
这将缓冲器转储清除到操作系统,并且一旦这样做,就不存在交织或丢失输出的可能性。
tv6aics14#
缓冲头痛.通常,你 * 可以 *,虽然,因为他们是同步的.那些告诉你不要这样做的人可能是那些记得使用多个io方法的痛苦,并希望从它中保存你的人.(只是不要混合任何一个与系统调用.那将是痛苦的.)
rhfm7lfc5#
库不应该使用printf、cout或任何其他I/O来处理标准句柄。它们应该使用回调例程来将输出委托给主程序选择的方法。
一个明显的例外是库的唯一目的是输出,但是主程序可以选择使用它,并且这个规则不禁止对库打开的文件描述符进行I/O。
这不仅可以解决这里提出的问题,而且还可以处理断开连接的操作(没有tty的linux程序,例如通过
nohup
或Win32服务运行)。yv5phkfx6#
我的看法,不一定正确,仅供参考。😄
概述
cout/wcout是C++世界的概念,C世界的等价术语是printf/wrpintf,这些机制用于将我们在应用程序中提供的内容转换为标准的输出流。
与C语言兼容是C的设计目标之一,也就是说,C的实现必须保证C++和C代码的混合正确执行。
问题很明显,C和C毕竟是两种不同的语言,C的cout/wcout和C的printf/wprintf都有自己的实现,比如自己的应用层缓冲区、自己的缓冲区刷新策略、自己的locale依赖......总之,cout/wcout和printf/wprintf是两种独立的操作机制,简单的混合会导致意想不到的结果,因此C++标准设计者必须开发一个可行的解决方案。
从编码者的Angular 来看,混合cout和printf的正确行为应该保证执行结果就像只使用cout或printf一样。为了达到这个效果,提出了与stdio同步的概念。在我看来,"stdio"特指C语言的I/O机制。printf/wprintf属于它。所以'sync to stdio'意味着同步C++的I/O机制到C的机制。我们可以使用方法
std::ios::sync_with_stdio
来启用/禁用同步,默认情况下是启用的。那么,"sync"到底是什么?如何同步到stdio?这取决于实现,我不知道细节。"sync"的概念似乎更像是"share",printf/wprintf的缓冲区与cout/wcout共享。或者cout/wcout直接使用print/wprintf的缓冲区。简而言之,如果我们启用"sync",cout/wcout就不再是独立的,通常是缓冲区,它依赖于C stdio,"同步"使C++和C的I/O过程就像一种语言一样。
因此,我们可以在C++代码中轻松地使用cout + printf或wcout + wprintf,方法是使用stdio来启用sync(默认情况下是启用的,我们不需要操作)。这个问题通过"sync"来解决。另一个难题是混合cout + wcout或混合printf + wprintf,可以吗?--这个主题在下面讨论。
cout
printf
工作在char
存储单元上,wcout
wprintf
工作在wchar_t
上,混用cout + wcout或printf + wprintf不涉及语言级别冲突,由于cout
wcout
属于同一种语言,因此printf
和wprintf
也属于同一种语言,这里问题的关键是'the orientation of the standard output stream'
。定向是什么意思?我认为它可以解释为粒度。正如我们所知,OOD是面向对象的设计,这意味着设计的粒度是对象。另一个例子是面向字节流的协议-TCP,这意味着如果我们构建基于TCP的应用程序,我们必须关注字节。回到正题,那么...标准输出流的方向是什么?答案是
byte
或wide byte
或其他我不确定的东西...标准输出流是面向字节的还是面向宽字节的,C ++/C语言如何确定哪一个?策略是查看第一个执行的I/O函数/方法的版本,如果它是字节版本,就像cout或printf,那么标准输出流被设置为面向字节的,否则如果它是宽字节版本,就像wcout或wprintf,则标准输出流是面向宽字节的。
我们为什么要关心标准输出流的方向呢?那是因为标准输出流的不同方向会影响内容的呈现。很容易这样想,方向决定了标准输出流处理/提取/翻译cout/wcout/printf/wprintf内容的粒度。试想一下,我们首先使用WCOUT触发标准输出流被设置为面向宽字节,然后我们通过COUT提供一些内容,结果是面向宽字节的标准输出流接收到一组经过字节处理的内容,最后,打印到连接到标准输出流的设备的内容未定义。
另外,在我的实际开发中,我发现还有另外一种标准输出流定向的情况,在禁用同步开关stdio-
std::ios::sync_with_stdio(false)
后,无论是先调用wcout再调用cout还是先调用cout再调用wcout,打印内容都是可以的!(当然,我们必须设置locale,但那是另外一个主题),在这种情况下,我调用fwide(stdout, 0)
总是返回0,这意味着当前的标准输出流方向未定。未决定的状态是因为标准输出流可以自动切换到合适的方向?还是未决定的状态意味着标准输出流处于万能状态?我不知道...一个特例。Windows世界中提供了一个名为
_setmode
的函数,该函数用于设置特定流的翻译模式。经过我的尝试,我猜所谓的"翻译模式"相当于流的方向。但是,使用_setmode
设置流方向似乎在底层设置了一些非标准的标志值!因为在我调用_setmode
设置某些模式之后(例如:_O_WTEXT,_O_U8TEXT,_O_U16TEXT ...),如果我调用fwide
来检查当前的流方向,就会崩溃。可能是fwide
查询了一个无法理解的数据,所以崩溃了!一些演示
我编写了一个函数
checkStdoutOrientation
来获取标准输出流方向演示01:首先调用wcout,然后调用cout
debian10 buster + gcc 8.3.0
Win10 + vs2022
演示02:首先调用cout,然后调用wcout
debian10 buster + gcc 8.3.0
Win10 + vs2022
演示03:首先调用wprintf,然后调用printf
结论与Demo01相同
演示04:首先调用printf,然后调用wprintf
debian10 buster + gcc 8.3.0
Win10 + vs2022
演示05:禁用同步与stdio,然后wcout,cout
debian10 buster + gcc 8.3.0
Win10 + vs2022
演示06:混合cout,打印
debian10 buster + gcc 8.3.0
Win10 + vs2022
演示07:打印非ASCII字符--方法A
debian10 buster + gcc 8.3.0
global(myloc)
代码设置为en_US. UTF-8。Win10 + vs2022
演示08:打印非ASCII字符--方法B
debian10 buster + gcc 8.3.0
imbue
方法将wout的locale设置为en_US. UTF-8,如果不这样做,wcout将打印类似"??"的内容;std::locale::global(myloc);
,所以stdio的语言环境仍然是C语言环境。Win10 + vs2022
小行星
std::locale::global(myloc);
代码,打印内容是ok!所以,我认为windows实现是小特殊,wcout可能依赖于更多的东西,需要改变locale由全局locale设置.演示09:打印非ASCII字符--方法C
此演示依赖于windows平台。
Win10 + vs2022
在_setmode之后,全局和wcout语言环境仍然是C语言环境;
为什么wcout和wprintf都能正确打印内容?我猜可能是windows在标准输出流之后实现了一种机制,通过_setmode指定的模式来翻译内容。