char与wchar_t的区别

7

我要尝试打印一个wchar_t*类型的字符串。 以下是代码:

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

char *ascii_ = "中日友好";  //line-1
wchar_t *wchar_ = L"中日友好";  //line-2

int main()
{
    printf("ascii_: %s\n", ascii_);  //line-3
    wprintf(L"wchar_: %s\n", wchar_);  //line-4
    return 0;
}

//Output
ascii_: 中日友好

问题:

  1. 显然,我不应该在第一行中将CJK字符分配给char*指针,但我却这样做了,而第三行的输出是正确的。为什么?printf()在第三行如何给我提供非ASCII字符?它是否知道编码方式?

  2. 我假设第二行和第四行的代码是正确的,但为什么我没有得到第四行的输出?


你在使用哪个编译器?GCC 在大多数平台上默认使用 Utf-8 编码。对我来说,这似乎是一个编码问题。 - cyco130
3个回答

9
首先,在源代码中使用非ASCII字符通常不是一个好主意。可能发生的情况是,中文字符被编码为与ASCII兼容的UTF-8格式。
至于为什么wprintf()不起作用,这与流方向有关。每个流只能设置为普通或宽字符,一旦设置就无法更改。第一次使用时进行设置(由于使用了printf,因此使用的是ASCII)。之后,由于方向不正确,wprintf将无法工作。
换句话说,一旦使用了printf(),就需要继续使用printf()。同样地,如果从wprintf()开始,就需要继续使用wprintf()
不能混合使用printf()wprintf()。(除了在Windows上)
编辑:
回答关于wprintf行即使单独使用也无法工作的问题。这可能是因为编译代码时,中日友好的UTF-8格式存储到wchar_中。然而,wchar_t需要4字节的Unicode编码。(在Windows中是2字节)
因此,我可以想到两个选项:
1. 不要使用wchar_t,只使用多字节的char。这是简单的方法,但如果用户的系统未设置为中文区域,则可能会出现问题。
2. 使用wchar_t,但需要使用Unicode转义序列对中文字符进行编码。这显然会使源代码难以阅读,但它将在任何可以打印中文字符字体的机器上工作,而不受区域设置的影响。

如果使用Unicode转义序列,我需要找出每个中文字的序列,对吧?那将会是很多工作要做,:P - Alcott
1
正确。但是我相信这种情况很常见,你可以在网上找到一个工具,只需复制并粘贴中文文本,它就会给你提供Unicode转义序列。为了保持代码的可读性,你可以将实际的中文文本与转义序列放在注释旁边。 - Mysticial
1
我们开始吧,我已经找到一个:http://www.rishida.net/tools/conversion/:`中日友好 -> "\u4E2D\u65E5\u53CB\u597D"`。 - Mysticial

6

第一行并不是ascii码,它的编码方式取决于编译器在编译时所使用的多字节编码方式。在现代系统中,这可能是UTF-8。

printf 函数不知道编码方式。它只是将字节发送到 stdout,只要编码方式匹配,一切都没问题。

你应该注意的一个问题是,在同一个 FILEstdout) 上混合使用基于字符和宽字符的 IO 操作将导致未定义行为。在第一次操作之后,FILE 就有了“方向”(字节或宽字符),此后任何尝试执行相反方向操作的尝试都会导致未定义行为。


我注释掉了printf()这一行,我得到了一些输出,但没有中文字符。为什么? - Alcott
本地编码是什么?如何修复它? - Alcott
@Alcott:我刚刚更新了我的回答。我本来想把它作为评论添加在这里,但是太长了。 - Mysticial

1

你忽略了一个步骤,因此想法错误。

你有一个包含字节的C文件。你有一个“ASCII”字符串和一个宽字符串。

ASCII字符串将字节按照第一行中的方式输出。只要用户端的编码与程序员端的编码相同,这就可以正常工作。

宽字符串首先将给定的字节解码为Unicode代码点并存储在程序中-也许在你这边出了问题。在输出时,它们根据用户端的编码再次进行编码。这确保这些字符被发射为它们预期的样子,而不是输入的样子。

要么你的编译器假设了错误的编码,要么你的输出终端设置错误。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接