当我使用 newlocale() 和 uselocale() 而不是 setlocale() 时,mbrtowc() 无法转换

mbrtowc() fails to convert when I'm using newlocale() and uselocale() instead of setlocale()

提问人:Calmarius 提问时间:3/23/2023 最后编辑:Calmarius 更新时间:3/24/2023 访问量:39

问:

我想转换 UTF-8 字符串宽字符表示以使用代码点。为此,我在 Linux 上调用 uselocale() 以仅更改当前线程的区域设置。但出于某种原因,它似乎没有达到我的期望。这是一个最小的程序:

#define _XOPEN_SOURCE 700
#include <locale.h>
#include <wchar.h>
#include <stdio.h>
#include <assert.h>

int main()
{
    locale_t loc = newlocale(LC_ALL, "en_US.UTF-8", (locale_t)0);
    assert(loc);
    locale_t prevLocale = uselocale(loc);
    assert(prevLocale);

    wchar_t res;
    char src[] = "á";
    mbstate_t mbs = {0};
    int v = (int)mbrtowc(&res, src, sizeof(src), &mbs);
    printf("%d\n", v);
    perror("Failed to convert char");

    return 0;
}

我希望它能够拾取 UTF-8 语言环境并转换字符,但是当我运行它时,我得到:

-1
Failed to convert char: Invalid or incomplete multibyte or wide character

源文件编码为 UTF-8。所以这不是问题。

如果我改为调用进程范围,如下所示:setlocale

#define _XOPEN_SOURCE 700
#include <locale.h>
#include <wchar.h>
#include <stdio.h>
#include <assert.h>

int main()
{
    setlocale(LC_ALL, "en_US.UTF-8");

    wchar_t res;
    char src[] = "á";
    mbstate_t mbs = {0};
    int v = (int)mbrtowc(&res, src, sizeof(src), &mbs);
    printf("%d\n", v);
    perror("Failed to convert char");

    return 0;
}

转换成功:

2
Failed to convert char: Success

我只想为线程设置区域设置,以避免干扰进程范围的设置,然后稍后我会将其还原为原始区域设置。

我发现 uselocale() 覆盖了进程范围的区域设置,因此在调用 uselocale() 后,setlocale() 在使用线程级区域设置时将不起作用。所以uselocale()确实有一些影响。但它的行为似乎像“C”语言环境。

我在这里做错了什么?

C Linux UTF-8 语言环境

评论

0赞 chux - Reinstate Monica 3/24/2023
也许将标题更改为包含,因为这是错误源。newlocale()

答:

3赞 KamilCuk 3/24/2023 #1

newlocale()采用_MASK而不是区域设置。请参见手册页。

locale_t loc = newlocale(LC_ALL_MASK, "en_US.UTF-8", (locale_t)0);

评论

0赞 Calmarius 3/24/2023
确实是这样。出于某种原因,我认为LC_ALL已经是一个位掩码了!