使用printf打印UTF-8字符串 - 宽字符串与多字节字符串文字

tep*_*pic 21 c unicode printf utf-8 multibyte

在这些语句中,两者都使用相同的编码(UTF-8)输入到源代码中并且语言环境设置正确,它们之间是否存在实际差异?

printf("? ??????????? ?? ???? ?????\n");
printf("%ls", L"? ??????????? ?? ???? ?????\n");
Run Code Online (Sandbox Code Playgroud)

因此有什么理由在做输出时更喜欢一个而不是另一个?我想第二个表现得差一点,但是它对多字节文字有任何优势(或劣势)吗?

编辑:这些字符串打印没有问题.但是我没有使用宽字符串函数,因为我也希望能够使用printf等等.所以问题是打印任何不同的方式(鉴于上面列出的情况),如果是这样,第二个方法有任何优势吗?

编辑2:按照下面的评论,我现在知道这个程序有效 - 我认为这是不可能的:

int main()
{
    setlocale(LC_ALL, "");
    wprintf(L"? ??????????? ?? ???? ?????\n");  // wide output
    freopen(NULL, "w", stdout);                 // lets me switch
    printf("? ??????????? ?? ???? ?????\n");    // byte output
}
Run Code Online (Sandbox Code Playgroud)

EDIT3:我通过观察这两种类型的情况做了一些进一步的研究.拿一个更简单的字符串:

wchar_t *wides = L"£100 ?";
char *mbs = "£100 ?";
Run Code Online (Sandbox Code Playgroud)

编译器生成不同的代码.宽字符串是:

.string "\243"
.string ""
.string ""
.string "1"
.string ""
.string ""
.string "0"
.string ""
.string ""
.string "0"
.string ""
.string ""
.string " "
.string ""
.string ""
.string "\300\003"
.string ""
.string ""
.string ""
.string ""
.string ""
Run Code Online (Sandbox Code Playgroud)

而第二个是:

.string "\302\243100 \317\200"
Run Code Online (Sandbox Code Playgroud)

看看Unicode编码,第二个是普通的UTF-8.宽字符表示是UTF-32.我意识到这将取决于实现.

那么文字的宽字符表示可能更便携?我的系统不会直接打印UTF-16/UTF-32编码,因此它会自动转换为UTF-8进行输出.

Lih*_*ihO 27

printf("? ??????????? ?? ???? ?????\n");
Run Code Online (Sandbox Code Playgroud)

打印字符串文字(const char*特殊字符表示为多字节字符).虽然您可能会看到正确的输出,但在处理非ASCII字符时可能会遇到其他问题.例如:

char str[] = "????";
printf("%d %d\n", sizeof(str), strlen(str));
Run Code Online (Sandbox Code Playgroud)

输出9 8,因为这些特殊字符中的每一个都用2 char秒表示.

使用L前缀时,由宽字符(const wchar_t*)和%ls格式说明符组成的文字会导致这些宽字符转换为多字节字符(UTF-8).请注意,在这种情况下,应该适当地设置区域设置,否则此转换可能导致输出无效:

#include <stdio.h>
#include <wchar.h>
#include <locale.h>

int main(void)
{
    setlocale(LC_ALL, "");
    printf("%ls", L"? ??????????? ?? ???? ?????");
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

但是,当使用宽字符时,某些事情可能会变得更复杂,但其他事情可能变得更简单,更直接.例如:

wchar_t str[] = L"????";
printf("%d %d", sizeof(str) / sizeof(wchar_t), wcslen(str));
Run Code Online (Sandbox Code Playgroud)

5 4按照人们自然期望的方式输出.

一旦您决定使用宽字符串,wprintf可以直接用于打印宽字符.这里还值得注意的是,在Windows控制台的情况下,stdout应通过调用_setmode以下方式将其转换模式显式设置为其中一种Unicode模式:

#include <stdio.h>
#include <wchar.h>

#include <io.h>
#include <fcntl.h>
#ifndef _O_U16TEXT
  #define _O_U16TEXT 0x20000
#endif

int main()
{
    _setmode(_fileno(stdout), _O_U16TEXT);
    wprintf(L"%s\n", L"? ??????????? ?? ???? ?????");
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

  • UTF-16不是**"宽",这个神话仍然存在,这真是一种耻辱.有超过2 ^ 16个Unicode字符,UTF-16用**变量**宽度编码它们,宽度为一个或两个16位代码单元.如果你想要"宽",你必须求助于UTF-32.让我们不要陷入这样的陷阱:"n"对每个人都应该足够了,*再次*. (6认同)
  • 谢谢.我正专注于与Unicode相关的强大东西,而且看到关于这个主题的半生不熟的知识到底是多么令人难过.UTF-16是一个很好的例子:有效的多字节编码,嵌入零字节.令人惊讶的是,有多少古老的希腊语,一些扩展的CJK或一两个象形文字,可以用多少"Unicode感知"软件制作barf.更不用说结合人物和其他这样的细节.;-) (4认同)