2014-02-12 100 views
1

考慮下面的代碼:的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實施中真的是一個錯誤?或者只是在這種情況下規格不夠嚴格,而且都可以被視爲正確的結果?

+1

您明確地將您的區域設置爲CP1252,它是一個8位編碼。如果有的話,我會說異常版本是Linux版本,因爲在0xff之後應該沒有可用的字符(並且在wstring中每個字符至少會浪費1個字節)。 –

+1

MSVC CRT的記錄行爲:「towupper的大小寫轉換是特定於locale的」。對於Linux:「這個函數不適合處理Unicode字符」。 –

+0

@ user846250據我所知,towupper應該將輸入視爲一個Unicode代碼點,因此不會根據任何代碼頁來解釋它。所以語言環境的代碼頁設置應該是不相關的。有一個toupper變體(沒有'w')應該根據代碼頁來解釋輸入。 –

回答

1

從這個問題的評論看來,似乎沒有「真正的」解決方案; C或C++標準在字符編碼方面不夠嚴格,所以我們不能對區域敏感的結果有真正的期望。

對於我在Windows上的具體使用情況,CharUpperW竟然是一個可行的選擇,雖然它依賴於平臺。