为什么 wcrtomb 仅支持 ASCII?

问题描述 投票:0回答:1

在我的系统上wcrtomb()似乎认为“窄多字节表示”意味着“仅限ASCII”,即使我使用 -fexec-charset=utf-8 进行编译。我的印象是 -fexec-charset gcc 标志控制“窄多字节表示”的含义,而 wcrtomb 从“宽字符集”转换为“窄多字节表示”。如果“窄多字节表示”是 utf-8 并且“宽字符集”是 utf-32,那么 wcrtomb 应该从 utf-32 转换为 utf-8。我知道实际的答案可能只是使用显式的utf-32到utf-8转换,而不是依赖于“宽字符集”和“窄多字节表示”。我想了解为什么这没有达到我的预期。

#include <clocale>
#include <cwchar>
#include <iostream>
#include <string>
#include <vector>
#include <fstream>

int main() {
    wchar_t max = 0x10FFFF;
    std::vector<char> out(MB_CUR_MAX * max);
    char *end = &out[0];
    for(wchar_t c = 0; c < max; ++c) {
        std::mbstate_t state{};
        std::size_t ret = wcrtomb(end, c, &state);
    if(ret != static_cast<std::size_t>(-1)) {
        end += ret;
    }
    }
    std::ofstream outfile("out", std::ios::out | std::ios::binary); 
    outfile.write(&out[0], end - &out[0]);
    return 0;
}
(export LC_ALL=en_US.UTF-8; g++ -fwide-exec-charset=utf-32le -fexec-charset=utf-8 main.cpp && ./a.out && cat -v ./out && echo)
^@^A^B^C^D^E^F^G^H  
^K^L^M^N^O^P^Q^R^S^T^U^V^W^X^Y^Z^[^\^]^^^_ !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~^?

我尝试过的:

  1. 设置 -fexec-charset=utf-8 即使 gcc 文档说这是默认值
  2. 设置 -fwide-exec-charset=utf-32le 即使这似乎已经是这种情况
  3. 设置 LC_ALL=en_US.UTF-8 用于编译和执行
  4. 使用 clang 而不是 gcc 进行编译(不支持 -fwide-exec-charset,但打印
    __clang_wide_literal_encoding__
    表示 UTF-32)

系统信息: Ubuntu 22.04.3 LTS g++ (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0 Ubuntu clang 版本 14.0.0-1ubuntu1.1

c++ c gcc encoding
1个回答
0
投票

为什么 wcrtomb 仅支持 ASCII?

因为你的程序中的区域设置是

C
。 C 程序启动时的初始语言环境是
C
,即 ASCII。转换取决于区域设置。如果你想从环境继承语言环境,你必须
setlocale("", LC_ALL)

© www.soinside.com 2019 - 2024. All rights reserved.