【问题标题】:Displaying wide character in hexadecimal hex shows unexpected result以十六进制显示宽字符显示意外结果
【发布时间】:2020-11-05 11:25:07
【问题描述】:

我试图以十六进制显示一个宽字符,它给了我意想不到的结果,它总是像 2 位十六进制和我的代码。

#include "stdlib.h"
#include "stdio.h"
#include"wchar.h"
#include "locale.h"
int main(){
    
    setlocale(LC_ALL,"");
    wchar_t ch;
    wscanf (L"%lc",&ch);
    wprintf(L"%x \n",ch);
  return 0;
}

输入:Ω

结果:0xea

预期结果:0xcea9

我多次更改setlocale,但结果始终相同。

通知

当输入值小于 1 字节时,它按预期工作。

【问题讨论】:

  • “将宽字符转换为十六进制”是什么意思?您能否举一个您希望看到的字符示例和输出示例? it gives me unexpected results 究竟是什么结果?能否请您添加 #includeint main - 第 1000 次编写它们不好玩?
  • 旁白:#include "stdlib.h"(等)应该是#include <stdlib.h>,除非您有自己的库版本可以使用而不是提供的库版本。
  • @kamilCuk 好的,我澄清了我的代码,你能帮忙吗
  • @WeatherVane 我也试过了,但没有任何改变

标签: c utf-8 hex


【解决方案1】:

请注意,您应该使用<..> 来包含标准标头。 wprintf("%x", ch) 行无效,因为它很可能是未定义的行为 - ch(可能)不是 unsigned int,您不能在其上应用 %x

您期望宽字符以 UTF-8 格式存储。好吧,这没有多大意义,他们不是。您的程序以 多字节编码 读取 sequence 字节,然后将该字节序列转换(取决于语言环境)为宽字符编码。宽字符编码(通常)保持不变,在 linux 上应该是 UTF-32。语言环境影响多字节字符与宽字符之间的转换方式,而不是宽字符的表示。

以下程序:

#include <stdlib.h>
#include <stdio.h>
#include <wchar.h>
#include <locale.h>
int main(){
    setlocale(LC_ALL,"");
    wchar_t ch;
    int cnt = wscanf(L"%lc",&ch);
    if (cnt != 1) { /* handle error */ abort(); }
    wprintf(L"%x\n", (unsigned int)ch);
    return 0;
}

在 linux 上输入Greek Capital Letter Omega Ω U+3A9 时,程序输出3a9。实际发生的是终端读取 UTF-8 编码字符,因此它读取 两个 字节 0xCE 0xA9,然后将它们转换为 UTF-32 并将结果存储在宽字符中。您可以将宽字符从宽字符编码 (UTF-32) 转换为多字节字符编码(UTF-8 应该是默认值,但取决于区域设置)并以多字节字符编码打印代表字符的字节:

char tmp[MB_CUR_MAX];
int len = wctomb(tmp, ch);   // prefer wcrtomb
if (len < 0) { /* handle error */ abort(); }
for (int i = 0; i < len; ++i) {
    wprintf(L"%hhx", (unsigned char)tmp[i]);
}
wprintf(L"\n");

这将在我的平台上输出cea9

【讨论】:

  • 对不起,我的回复迟了,所以经过多次尝试后我发现问题是我使用的是 windows,因此 windows 的编码系统是English_United States.1252,即使我也无法更改它最后使用 set local 我会认为你的答案是正确的,因为它给了我一个提示,谢谢
  • 嗯,CP1252编码中没有欧米茄字母。 Windows 使用 UTF-16 来表示宽字符。哎呀,所以wctomb 失败了,因为无法将 UTF-16 中的欧米茄字符表示为 CP1252 中的多字节编码。
猜你喜欢
  • 2014-12-20
  • 2016-06-28
  • 2011-04-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-10-21
  • 2014-03-11
  • 2014-05-24
相关资源
最近更新 更多