[英]c++ Mixing printf with wprintf (or cout with wcout)
我知道您不应该将打印与 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);
实际上做了这个把戏......(注意是假的,而不是我期望的那样......),唯一困扰我的是,我不明白为什么以及如何弄清楚:-(
您应该能够混合它们,但它们通常使用单独的缓冲机制,因此它们相互重叠:
printf("hello world");
cout << "this is a suprise";
可能导致:
hellothis是一个令人惊讶的世界
您没有提供足够的信息来诊断应用程序中printf()的问题,但我怀疑您有多个c运行时(代码中有一个,printf()代码中有一个)并且存在冲突。
我想你在谈论std::ios_base::sync_with_stdio
,但是IIRC默认是打开的。
printf()和cout缓冲区默认是同步的,或者实际上是相同的缓冲区。 如果您遇到缓冲问题,显而易见的解决方案是在每次输出后刷新缓冲区:
fflush( stdout );
cout.flush();
这会将缓冲区刷新到操作系统,一旦完成,就不会有交错或输出丢失的可能性。
缓解头痛。 通常,你可以 ,因为它们是同步的。 告诉你不要的人可能是那些记得使用多种io方法并希望从中拯救你的痛苦的人。 (只是不要与系统调用混合。这将是痛苦的。)
库不应将printf,cout或任何其他I / O用于标准句柄。 他们应该使用回调例程将输出委托给主程序选择的方法。
一个明显的例外是一个库,其唯一目的是输出,但它是主程序使用它的选择。 此规则不禁止I / O到库打开的文件描述符。
这不仅可以解决此处提出的问题,而且还可以解决断开连接的操作(没有tty的linux程序,例如通过nohup
或Win32服务运行)。
std::ios::sync_with_stdio
来启用/禁用同步,默认情况下启用。cout
printf
在char
存储单元上工作,而wcout
wprintf
在wchar_t
上工作。 混合使用 cout+wcout 或 printf+wprintf 不涉及语言层面的冲突。 因为cout
wcout
属于同一种语言,所以printf
和wprintf
也是如此。 这里问题的关键是'the orientation of the standard output stream'
。byte
或wide byte
或其他我不确定的东西......std::ios::sync_with_stdio(false)
后,无论我先调用wcout再调用cout还是调用cout再调用wcout,打印内容都可以,(当然,我们必须设置locale。但那是另一个主题),在这种情况下,我调用fwide(stdout, 0)
总是返回 0,这意味着当前标准 output stream 方向未定,是否由于标准 output stream 而未定 state 可以自动切换到合适的方向? 还是未定意味着万能的state中的标准output stream? 我不知道..._setmode
的 function,这个 function 用于设置特定流的转换模式。 经过我的尝试,我猜所谓的“翻译模式”相当于 stream 方向。 但是,使用_setmode
设置 stream 方向似乎在底层设置了一些非标准标志值! 因为在我调用_setmode
设置某些模式(例如 _O_WTEXT、_O_U8TEXT、_O_U16TEXT...)之后,如果我调用fwide
尝试检查当前的 stream 方向,就会发生崩溃。 可能是fwide
查询了一个看不懂的数据,所以崩溃了!我写了一个 function checkStdoutOrientation
来获得标准的 output stream 方向
void checkStdoutOrientation()
{
std::fstream fs("result.txt", std::ios::app);
int ret = fwide(stdout, 0);
if (ret > 0) {
fs << "wide byte oriented\n";
} else if (ret < 0) {
fs << "byte oriented\n";
} else {
fs << "undecided oriented\n";
}
fs.close();
}
#include <cstdio>
#include <iostream>
#include <fstream>
int main()
{
checkStdoutOrientation();
std::wcout << "456" << std::endl;
checkStdoutOrientation();
std::cout << "123" << std::endl;
checkStdoutOrientation();
return 0;
}
我的理解:
- 首先调用 wcout,因此标准 output stream 是面向宽字节的;
- 正因为上述情况,cout处理的内容不能用标准output stream处理,所以“123”无法打印;
我的理解:
- 看来,windows不符合标准,标准output stream始终未定方向;
- 只是因为标准output stream的未定方向,所有内容都是打印出来的。
#include <cstdio>
#include <iostream>
#include <fstream>
int main()
{
checkStdoutOrientation();
std::cout << "123" << std::endl;
checkStdoutOrientation();
std::wcout << "456" << std::endl;
checkStdoutOrientation();
return 0;
}
我的理解:
- cout 首先被调用,所以标准 output stream 是面向字节的;
- 因为字节是比宽字节更小的粒度,所以 wcout 内容到字节导向标准 output stream 最终可以打印到控制台。
我的理解:
- 标准 output stream 始终未定方向;
- 所以所有内容都是打印的。
#include <cstdio>
#include <iostream>
#include <fstream>
int main()
{
checkStdoutOrientation();
wprintf(L"456\n");
checkStdoutOrientation();
printf("123\n");
checkStdoutOrientation();
return 0;
}
和Demo01的结论一样
#include <cstdio>
#include <iostream>
#include <fstream>
int main()
{
checkStdoutOrientation();
printf("123\n");
checkStdoutOrientation();
wprintf(L"456\n");
checkStdoutOrientation();
return 0;
}
我的理解:
- cout 首先被调用,所以标准 output stream 是面向字节的;
- 结果与Demo02不同,我不知道为什么“456”不显示。
我的理解:
- 与 Demo02 相同的结果。
#include <cstdio>
#include <iostream>
#include <fstream>
int main()
{
std::ios::sync_with_stdio(false);
checkStdoutOrientation();
std::wcout << "456" << std::endl;
checkStdoutOrientation();
std::cout << "123" << std::endl;
checkStdoutOrientation();
return 0;
}
我的理解:
- 禁用与 stdio 同步后,标准 output stream 始终未定方向;
- 所以所有内容都可以打印。
我的理解:
- 结果与 Demo01 相同。
#include <cstdio>
#include <iostream>
int main()
{
printf("1\n");
std::cout << "2\n";
printf("3\n");
std::cout << "4\n";
printf("5\n");
printf("\n");
std::ios::sync_with_stdio(false);
printf("1\n");
std::cout << "2\n";
printf("3\n");
std::cout << "4\n";
printf("5\n");
return 0;
}
我的理解:
- 默认情况下启用与 stdio 的同步,因此混合 cout 和 printf 就像调用 cout 或 printf 一样工作。
- 禁用与 stdio 同步后,cout 将独立工作,cout 和 printf 各司其职,因此打印内容乱序。
我的理解:
- Windows 仍然很特别,无论是否禁用与 stdio 的同步,混合 cout 和 printf 就像调用 cout 或 printf 一样工作。
#include <cstdio>
#include <iostream>
int main()
{
std::locale myloc("en_US.UTF-8");
std::locale::global(myloc); // this setting does not affect wcout
std::wcout << L"漢字\n";
wprintf(L"漢字\n");
return 0;
}
我的理解:
- 设置全局语言环境不影响 wcout,这个 wcout 的语言环境仍然是 C 语言环境。 因为wcout是一个object,它的locale在object构建的时候就已经设置好了。
- 那么既然如此,为什么wcout可以打印出内容呢? 不要忘记 C++ 的 iostream 默认与 stdio 同步,我们可以简单地认为,wcout 在 stdio 的缓冲区上工作,并且 stdio 已经由
global(myloc)
代码设置为 en_US.UTF-8。
我的理解:
- 没什么特别的;
#include <cstdio>
#include <iostream>
int main()
{
std::ios::sync_with_stdio(false);
std::locale myloc("en_US.UTF-8");
// std::locale::global(myloc);
std::wcout.imbue(myloc);
std::wcout << "wcout> " << L"漢字\n";
wprintf(L"wprintf> 漢字\n");
return 0;
}
我的理解:
- 由于禁用了与 stdio 的同步,wprintf 和 wcout 分开工作,所以打印顺序不对;
- 仍然由于同步禁用,wcout 应该独立工作,所以我们必须通过
imbue
方法将 wout 的语言环境设置为 en_US.UTF-8,如果不这样做,wcout 将打印类似“??”的内容;- wprintf print "??", 那是因为我们注释掉了
std::locale::global(myloc);
,因此 stdio 的语言环境仍然是 C 语言环境。
我的理解:
- printf和cout print always in order,这是windows特别的地方,这个已经讲过好几次了;
- wprintf print empty 相当于“??” 在 linux;
- 所以,新的是乱码! 我尝试取消注释
std::locale::global(myloc);
代码,打印内容没问题,所以,我认为 windows 实现没什么特别的。 wcout 可能取决于更多需要通过全局区域设置更改区域设置的东西。
本demo依赖windows平台。
#include <cstdio>
#include <iostream>
int main()
{
_setmode(_fileno(stdout), _O_WTEXT); // Unique function to windows
std::wcout << "wcout> " << L"漢字\n";
wprintf(L"wprintf> 漢字\n");
return 0;
}
我的理解:
- _setmode 之后,globale 和 wcout locale 仍然是 C locale;
- 为什么wcout和wprintf都能正确打印内容? 我想也许 windows 在标准 output stream 之后实施了一种机制,以通过 _setmode 指定模式翻译内容。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.