考虑下面的代码:的Visual C++:越野车towupper
#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;
}
}
如果我编译并在Visual Studio 2010(也2013)运行它,结果是:
set locale: English_United States.1252
towupper(0xff) = 0x9f
在Linux上用gcc :
set locale: en_US.cp1252
towupper(0xff) = 0x178
towupper的结果在两个平台上是不同的,linux/gcc给出的答案似乎对我来说是正确的,因为t他0x178(Ÿ)是0xff(ÿ)的正确大写Unicode代码点。
但是,0x9f也是Ÿ的代码点,但在使用的Windows-1252代码页中。因此,看起来好像Visual C的towupper会将输入视为一个窄字符,并根据预设的代码页进行解释。
至于我的理解,宽字符应该总是被解释为Unicode代码点,Windows/VC上的UTF-16和Linux/gcc上的UTF-32。我在这里错了吗,还是在Microsoft实施中真的是一个错误?或者只是在这种情况下规格不够严格,而且都可以被视为正确的结果?
您明确地将您的区域设置为CP1252,它是一个8位编码。如果有的话,我会说异常版本是Linux版本,因为在0xff之后应该没有可用的字符(并且在wstring中每个字符至少会浪费1个字节)。 –
MSVC CRT的记录行为:“towupper的大小写转换是特定于locale的”。对于Linux:“这个函数不适合处理Unicode字符”。 –
@ user846250据我所知,towupper应该将输入视为一个Unicode代码点,因此不会根据任何代码页来解释它。所以语言环境的代码页设置应该是不相关的。有一个toupper变体(没有'w')应该根据代码页来解释输入。 –