C 使用printf-wide与多字节字符串文本打印UTF-8字符串

C 使用printf-wide与多字节字符串文本打印UTF-8字符串,c,unicode,utf-8,printf,multibyte,C,Unicode,Utf 8,Printf,Multibyte,在这样的语句中,如果两者都以相同的编码(UTF-8)输入到源代码中,并且语言环境设置正确,那么它们之间有实际的区别吗 printf("ο Δικαιοπολις εν αγρω εστιν\n"); printf("%ls", L"ο Δικαιοπολις εν αγρω εστιν\n"); 因此,在进行输出时,是否有理由选择其中一个?我想第二个执行得比较差,但是它比多字节文字有什么优势(或劣势)吗 编辑:打印这些字符串时没有问题。但是我没有使用宽字符串函数,因为我希望能够同时使用prin

在这样的语句中,如果两者都以相同的编码(UTF-8)输入到源代码中,并且语言环境设置正确,那么它们之间有实际的区别吗

printf("ο Δικαιοπολις εν αγρω εστιν\n");
printf("%ls", L"ο Δικαιοπολις εν αγρω εστιν\n");
因此,在进行输出时,是否有理由选择其中一个?我想第二个执行得比较差,但是它比多字节文字有什么优势(或劣势)吗

编辑:打印这些字符串时没有问题。但是我没有使用宽字符串函数,因为我希望能够同时使用
printf
等。因此,问题是这些打印方式是否有任何不同(鉴于上述情况),如果有,第二种打印方式是否有任何优势

EDIT2:根据下面的评论,我现在知道这个程序是有效的——我认为这是不可能的:

int main()
{
    setlocale(LC_ALL, "");
    wprintf(L"ο Δικαιοπολις εν αγρω εστιν\n");  // wide output
    freopen(NULL, "w", stdout);                 // lets me switch
    printf("ο Δικαιοπολις εν αγρω εστιν\n");    // byte output
}

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

wchar_t *wides = L"£100 π";
char *mbs = "£100 π";
编译器正在生成不同的代码。宽字符串是:

.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 ""
第二个是:

.string "\302\243100 \317\200"
看看Unicode编码,第二种是纯UTF-8。宽字符表示为UTF-32。我意识到这将取决于实施情况

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

printf("ο Δικαιοπολις εν αγρω εστιν\n");
打印字符串文字(
const char*
,特殊字符表示为多字节字符)。虽然您可能会看到正确的输出,但在处理此类非ASCII字符时可能会遇到其他问题。例如:

char str[] = "αγρω";
printf("%d %d\n", sizeof(str), strlen(str));
wchar_t str[] = L"αγρω";
printf("%d %d", sizeof(str) / sizeof(wchar_t), wcslen(str));
输出
9 8
,因为每个特殊字符都由2
char
s表示

当使用
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;
}
将输出自然期望的
54

一旦决定使用宽字符串,就可以使用它直接打印宽字符。这里还值得注意的是,对于Windows控制台,
stdout
的翻译模式应通过调用以下命令显式设置为Unicode模式之一:

#包括
#包括
#包括
#包括
#ifndef\u O\u 16文本
#定义_O_u16文本0x20000
#恩迪夫
int main()
{
_setmode(_fileno(stdout),_O_16text);
wprintf(L“%s\n”,L“Δοκαιπολιςεναγρωεστν”);
返回0;
}

这就是我:)
wprintf
也可以转换为多字节,但我对标准函数感兴趣。UTF-16不是“宽的”,很遗憾这一点仍然存在。有2^16个以上的Unicode字符,UTF-16使用一个或两个16位代码单元的可变宽度对其进行编码。如果你想“宽”,你必须求助于UTF-32。让我们不要再陷入那种认为
n
位应该对每个人都足够的陷阱。谢谢。我正在从事与Unicode非常相关的专业工作,看到有那么多关于这个主题的半生不熟的知识,我真是太难过了。UTF-16是一个完美的例子:它实际上是一种多字节编码,嵌入了零字节。令人惊讶的是,有多少“Unicode感知”软件可以通过一点古希腊语、一些扩展的CJK或一两个象形文字来实现。更不用说组合字符和其他细节了@DevSolar-我很高兴您认识到,作为古希腊语(除非是巧合):@DevSolar-
fwide
只能用于最初设置流,不幸的是,一旦定向,它就无法更改流。您说这两个示例都是用UTF-8输入的。在第二个示例行中,如果该文本实际上是UTF-8而不是宽编码,那么您可能不应该使用L前缀,因此您只需要使用
%s
而不是
%ls
。或者我仍然误解了这个问题。@AdrianMcCarthy-源代码中的两个字符串都是UTF-8,是的。但字符串文字始终是多字节的--“字符串文字是由零个或多个多字节字符组成的序列,用双引号括起来,如“xyz”。宽字符串文字是相同的,除了由字母L预先固定。AFAIR中,基本源字符集以外的任何字符(US-ASCII-7的子集)调用实现定义的行为,即此处讨论的所有内容都有效地取决于所使用的编译器。如果你真的想安全(便携),你必须求助于\u。。。而且\U…很可能是在实现方面。我想做的是一直切换到宽字符表示,但要坚持使用常规的stdio函数进行输出,这样就不会破坏与所有期望它们工作的东西的兼容性。我真的只是想知道我是否应该只使用多字节文字(如上所述),或者是否有理由使用宽文字。这很难解释,而且我做得不是很好!我非常确信不应该使用L“”,尤其是在平台窗口上。
#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;
}