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

标签 c unicode utf-8 printf multibyte

在像这样的语句中,两者都使用相同的编码 (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));

输出 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;
}

但是,虽然在使用宽字符时有些事情可能会变得更加复杂,但其他事情可能会变得更加简单和直接。例如:

wchar_t str[] = L"αγρω";
printf("%d %d", sizeof(str) / sizeof(wchar_t), wcslen(str));

将输出 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;
}

关于c - 使用 printf 打印 UTF-8 字符串 - 宽字符串文字与多字节字符串文字,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15528359/

相关文章:

c - fread() 无法正确写入字符串

c - C 中字符串反转意外输出

Java FTPClient listFiles返回带有unicode路径的空结果

c++ - 如何删除 C++ 中 UTF-8 字符串的最后一个字符?

c++ - 如何通过指针读取 UTF-8 字符?

C 编程 通过<time.h>的time(&start)函数改变程序结果

c - linux同进程下的线程如何分配stack或内存

python - UTF-8 在 Python 日志记录中,如何?

ruby-on-rails - Rails 3 无效的多字节字符 (US-ASCII)

swift - 如何在 Swift 中获取由整数表示的 Unicode 代码点?