我一直在测试将Unicode文本(如表情符号)写入CLI工具的控制台。我注意到,当使用wprintf输出一个emoji时,它会打印出两个问号(�),但当我使用WriteConsoleW时,它会输出得非常好。
测试代码(使用/utf-8
的MSVC和使用-municode
的MinGW编译)
#include <stdio.h>
#include <fcntl.h>
#include <io.h>
#include <Windows.h>
int wmain(int argc, const wchar_t *argv[]) {
_setmode(_fileno(stdout), _O_U16TEXT);
const wchar_t myString[] = L"😊\n";
wprintf(L"%s", myString);
WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE), myString, wcslen(myString), NULL, NULL);
}
输出量:
1条答案
按热度按时间jckbn6z71#
根据C语言规范
wprintf
系列函数与printf
类似函数的区别主要体现在两个方面:它们在格式字符串的语义解释上没有区别。特别是,
%s
转换说明符对wprintf()
的意义与对printf()
的意义完全相同:对应的参数是指向char
数组的第一个元素的指针--而不是wchar_t
。如果你想打印一个 wide 字符串,那么你需要使用适当的长度修饰符,得到%ls
。也就是说,请注意,您可以对常规
printf
执行相同的操作:.尽管您很可能会发现
printf
和wprintf
执行的代码转换存在差异。自从在C99中引入面向宽的I/O以来,情况一直如此。
根据微软
微软的C编译器和运行时库在很多方面都是不一致的。其中之一是
wprintf
系列函数的行为,因为wprintf
将不带宽度修饰符的%c
和%s
转换规范分别解释为对应于wchar_t
和wchar_t *
参数。它将
%ls
识别为对应于所有函数的宽字符串,并将%lc
识别为对应于所有函数的wchar_t
(后者仍然可能不符合标准,因为标准说%lc
对应于wint_t
)。它们还识别MS特定的%hc
和%hs
,分别对应于所有功能的char
和char *
。| 建议:|
| --|
| 对于宽字符串和宽字符,始终使用
%ls
和%lc
转换说明符,以及所有格式化的I/O函数(常规和宽)。这就是C语言所需要的,它将与MS库一起工作。|一般注意事项
C语言说明了哪些数据被发送到外部设备,但不说明这些设备如何处理这些数据。特定于Windows的
_setmode()
在这个领域运行,各种报告建议您的_setmode(_fileno(stdout), _O_U16TEXT)
应该使wprintf
产品在您的情况下做正确的事情。我没有足够的信息来确定发生了什么--是关于你的控制台配置的吗?关于你如何在源文件中编码数据的一些事情?在你使用的Windows或MS CRT版本中,是否有什么东西的工作方式与它工作的版本不同?你的编译器选项中是否有什么东西导致了问题?在任何情况下,UTF-16都是一种可怕的编码。在你可以摆脱它的地方,UTF-8在几乎所有方面都更可取。常规
printf()
不需要任何特殊配置来发送UTF-8字符串(它无法将它们与任何其他C字符串区分开来),因此使用UTF-8编码的源代码并将控制台配置为UTF-8模式将是一种合理的尝试方法。