C++ visualc&x2B+;:四轮拖车

C++ visualc&x2B+;:四轮拖车,c++,visual-studio,gcc,unicode,C++,Visual Studio,Gcc,Unicode,给定以下代码: #include <iostream> #include <cwctype> #include <clocale> int main() { wchar_t c = L'\u00ff'; // ÿ LATIN SMALL LETTER Y WITH DIAERESIS // → 0178 Ÿ latin capital letter y with diaeresis std::cout <

给定以下代码:

#include <iostream>
#include <cwctype>
#include <clocale>

int main()
{
    wchar_t c = L'\u00ff'; // ÿ LATIN SMALL LETTER Y WITH DIAERESIS
                // → 0178 Ÿ latin capital letter y with diaeresis

    std::cout << std::hex << std::showbase;
#ifdef WIN32
    const char * lcc = setlocale(LC_ALL, "English");
#else
    const char * lcc = std::setlocale(LC_ALL, "en_US.cp1252");
#endif
    if(lcc) {
        std::cout << "set locale: " << lcc << std::endl;
        std::cout << "towupper(" << (std::wint_t)c << ") = " << towupper(c) << '\n';
    } else {
        std::cout << "failed to set locale" << std::endl;
    }
}
在使用gcc的Linux上:

set locale: en_US.cp1252
towupper(0xff) = 0x178
towupper的结果在两种平台上是不同的,linux/gcc给出的答案对我来说似乎是正确的,因为0x178(Ÿ)是0xff(ÿ)的正确大写Unicode代码点

然而,0x9f也是Ÿ的代码点,但在使用的Windows-1252代码页中。因此,看起来就像Visual C的towupper将输入视为窄字符,并根据预设的代码页对其进行解释


就我的理解而言,宽字符应始终解释为Unicode代码点,Windows/VC上为UTF-16,Linux/gcc上为UTF-32。这是我错了,还是说这真的是Microsoft实现中的一个bug?或者只是规范在这种情况下不够严格,两者都可以被视为正确的结果?

从对问题的评论来看,似乎没有“真正”的解决方案;C或C++标准对于字符编码来说不够严格,所以我们不能对区域敏感结果有真正的期望。
对于我在Windows上的特定用例,charupper是一个可行的选项,尽管它依赖于平台。

您正在显式地将区域设置设置为CP1252,这是一种8位编码。如果有什么问题的话,我会说异常版本是Linux版本,因为除了0xff之外不应该有任何字符可用(并且WSString中的每个字符至少浪费1个字节)。MSVC CRT的记录行为:“towupper的大小写转换是特定于区域设置的”。对于Linux:“此函数不太适合处理Unicode字符”。@user846250就我所知,towupper应该将输入视为Unicode代码点,因此不能根据任何代码页对其进行解释。因此,区域设置的代码页设置应该是无关的。toupper变量(不带“w”)应该根据代码页解释输入。@HansPassant这可能是一个原因,因为没有详细说明依赖于语言环境的术语。但我认为它的语言环境依赖性是正确处理土耳其语虚线和无点I:I/ı和İ/I,而不是英语I/I大小写对。而且,Unicode代码点U+009F是一个控制字符,它不应该是任何其他字符的大写对。你认为C语言符合Unicode的假设是错误的。这不可避免地会让某些人感到不安,ISO委员会倾向于发现给每个人带来不便更容易。使用重症监护室。
set locale: en_US.cp1252
towupper(0xff) = 0x178