mbrtowc return -1 适用于嵌入式设备上的非 ASCII 字符,但不适用于 linux 计算机
mbrtowc return -1 for non ASCII characters on embedded device but not on linux computer
任务
目前我正在用纯 C 将设备的旧 DOS 代码移植到 Linux。文本是在 bitfonts 的帮助下绘制在表面上的。我编写了一个需要传递 Unicode 代码点的函数,然后绘制相应的字形(经过测试并适用于不同的 ASCII 和非 ASCII 字符)。旧的源代码使用 DOS 编码,但我正在尝试使用 UTF-8,因为需要多语言支持。我不能使用 SDL_ttf 或类似的函数,因为生成的字形 "precise" 不够。因此我必须坚持使用位字体。
问题
我编写了一个小的 C 测试程序来测试多字节字符到相应 Unicode 代码点的转换(受 http://en.cppreference.com/w/c/string/multibyte/mbrtowc 启发)。
#include <stdio.h>
#include <locale.h>
#include <string.h>
#include <wchar.h>
#include <stdint.h>
int main(void)
{
size_t n = 0, x = 0;
setlocale(LC_CTYPE, "en_US.utf8");
mbstate_t state = {0};
char in[] = "!°水"; // or u8"zß水"
size_t in_sz = sizeof(in) / sizeof (*in);
printf("Processing %zu UTF-8 code units: [ ", in_sz);
for(n = 0; n < in_sz; ++n)
{
printf("%#x ", (unsigned char)in[n]);
}
puts("]");
wchar_t out[in_sz];
char* p_in = in, *end = in + in_sz;
wchar_t *p_out = out;
int rc = 0;
while((rc = mbrtowc(p_out, p_in, end - p_in, &state)) > 0)
{
p_in += rc;
p_out += 1;
}
size_t out_sz = p_out - out + 1;
printf("into %zu wchar_t units: [ ", out_sz);
for(x = 0; x < out_sz; ++x)
{
printf("%u ", (unsigned short)out[x]);
}
puts("]");
}
输出符合预期:
Processing 7 UTF-8 code units: [ 0x21 0xc2 0xb0 0xe6 0xb0 0xb4 0 ]
into 4 wchar_t units: [ 33 176 27700 0 ]
当我在我的嵌入式 Linux 设备上 运行 这段代码时,我得到以下输出:
Processing 7 UTF-8 code units: [ 0x21 0xc2 0xb0 0xe6 0xb0 0xb4 0 ]
into 2 wchar_t units: [ 33 55264 ]
在 !
字符之后,mbrtowc 输出为 -1,根据文档,这是在发生编码错误时发生的。我用不同的符号测试了它,这个错误只发生在非 ASCII 字符上。 Linux 计算机
上从未发生过错误
附加信息
我在嵌入式设备上使用 PFM-540I Rev. B 作为 PC。 Linux 发行版是使用 Buildroot 构建的。
您需要确保 en_US.utf8
语言环境在嵌入式 Linux 构建中可用。默认情况下,Buildroot 以两种方式限制系统上安装的语言环境:
- 仅生成特定区域设置,如
BR2_GENERATE_LOCALE
配置选项所指定。默认情况下,此列表为空,因此您只能获得 C 语言环境。将此配置选项设置为 en_US.UTF-8
.
- 在构建结束时删除所有语言环境数据,
BR2_ENABLE_LOCALE_WHITELIST
中指定的除外。 en_US
已经是默认值,所以您可能不需要更改它。
请注意,如果更改这些配置选项,则需要进行完全干净的构建(使用 make clean; make
)才能使更改生效。
任务
目前我正在用纯 C 将设备的旧 DOS 代码移植到 Linux。文本是在 bitfonts 的帮助下绘制在表面上的。我编写了一个需要传递 Unicode 代码点的函数,然后绘制相应的字形(经过测试并适用于不同的 ASCII 和非 ASCII 字符)。旧的源代码使用 DOS 编码,但我正在尝试使用 UTF-8,因为需要多语言支持。我不能使用 SDL_ttf 或类似的函数,因为生成的字形 "precise" 不够。因此我必须坚持使用位字体。
问题
我编写了一个小的 C 测试程序来测试多字节字符到相应 Unicode 代码点的转换(受 http://en.cppreference.com/w/c/string/multibyte/mbrtowc 启发)。
#include <stdio.h>
#include <locale.h>
#include <string.h>
#include <wchar.h>
#include <stdint.h>
int main(void)
{
size_t n = 0, x = 0;
setlocale(LC_CTYPE, "en_US.utf8");
mbstate_t state = {0};
char in[] = "!°水"; // or u8"zß水"
size_t in_sz = sizeof(in) / sizeof (*in);
printf("Processing %zu UTF-8 code units: [ ", in_sz);
for(n = 0; n < in_sz; ++n)
{
printf("%#x ", (unsigned char)in[n]);
}
puts("]");
wchar_t out[in_sz];
char* p_in = in, *end = in + in_sz;
wchar_t *p_out = out;
int rc = 0;
while((rc = mbrtowc(p_out, p_in, end - p_in, &state)) > 0)
{
p_in += rc;
p_out += 1;
}
size_t out_sz = p_out - out + 1;
printf("into %zu wchar_t units: [ ", out_sz);
for(x = 0; x < out_sz; ++x)
{
printf("%u ", (unsigned short)out[x]);
}
puts("]");
}
输出符合预期:
Processing 7 UTF-8 code units: [ 0x21 0xc2 0xb0 0xe6 0xb0 0xb4 0 ]
into 4 wchar_t units: [ 33 176 27700 0 ]
当我在我的嵌入式 Linux 设备上 运行 这段代码时,我得到以下输出:
Processing 7 UTF-8 code units: [ 0x21 0xc2 0xb0 0xe6 0xb0 0xb4 0 ]
into 2 wchar_t units: [ 33 55264 ]
在 !
字符之后,mbrtowc 输出为 -1,根据文档,这是在发生编码错误时发生的。我用不同的符号测试了它,这个错误只发生在非 ASCII 字符上。 Linux 计算机
附加信息
我在嵌入式设备上使用 PFM-540I Rev. B 作为 PC。 Linux 发行版是使用 Buildroot 构建的。
您需要确保 en_US.utf8
语言环境在嵌入式 Linux 构建中可用。默认情况下,Buildroot 以两种方式限制系统上安装的语言环境:
- 仅生成特定区域设置,如
BR2_GENERATE_LOCALE
配置选项所指定。默认情况下,此列表为空,因此您只能获得 C 语言环境。将此配置选项设置为en_US.UTF-8
. - 在构建结束时删除所有语言环境数据,
BR2_ENABLE_LOCALE_WHITELIST
中指定的除外。en_US
已经是默认值,所以您可能不需要更改它。
请注意,如果更改这些配置选项,则需要进行完全干净的构建(使用 make clean; make
)才能使更改生效。