2012-10-24 61 views
21

功能c32rtomb和從<cuchar>/<uchar.h>mbrtoc32在C的Unicode TR(draft)爲UTF-32 和 「多字節字符」 之間執行轉換描述。c32rtomb轉換爲什麼編碼?

(...)如果s不是一個空 指針,c32rtomb函數確定以表示 對應於由c32 (包括任何移位序列給出的寬字符的多字節字符所需的字節數),並將多字節字符表示存儲在 中的第一個元素由s指向的數組中。 (...)

什麼是「多字節字符表示」?我在下面的程序的行爲實際上感興趣的是:

#include <cassert> 
#include <cuchar> 
#include <string> 

int main() { 
    std::u32string u32 = U"this is a wide string"; 
    std::string narrow = "this is a wide string"; 
    std::string converted(1000, '\0'); 
    char* ptr = &converted[0]; 
    std::mbstate_t state {}; 
    for(auto u : u32) { 
     ptr += std::c32rtomb(ptr, u, &state); 
    } 
    converted.resize(ptr - &converted[0]); 
    assert(converted == narrow); 
} 

是它保證持有的說法對嗎?


__STDC_UTF_32__定義的假設下工作。

回答

10

要使斷言保持爲真,必須使用c32rtomb()所使用的多字節編碼與用於字符串文本的編碼相同,至少就字符串中實際使用的字符而言。

C99 7.11.1.1/2指定setlocale()類別LC_CTYPE會影響字符處理函數以及多字節和寬字符函數的行爲。我沒有看到任何明確的承認,即效果是設置使用的多字節和寬字符編碼,但這是意圖。

因此c32rtomb()使用的多字節編碼是來自默認「C」語言環境的多字節編碼。

C++ 11 2.14.3/2指定執行編碼,寬執行編碼,UTF-16和UTF-32用於相應的字符和字符串文字。因此std::string narrow使用執行編碼來表示該字符串。

那麼這個字符串的「C」語言環境編碼和這個字符串的執行編碼是一樣的嗎?

C99 7.11.1.1/3指定「C」語言環境爲C語言翻譯提供「最小環境」。這種環境不僅包括字符集,還包括使用的特定字符代碼。所以我相信這不僅意味着「C」語言環境必須支持翻譯所需的字符(即基本字符集),而且「C」語言環境中的那些字符必須使用相同的字符代碼。

所有的字符在字符串文字是基本字符集的成員,因爲編譯器產生用於char字符串文字因此char32_t表示轉換到char「C」區域表示必須產生值的相同序列;該斷言必須成立。

我沒有看到任何暗示超出基本字符集的東西在執行編碼和「C」語言環境之間以兼容的方式得到支持,所以如果您的字符串文字使用基本字符集之外的任何字符,那麼那裏並不能保證這個主張會成立。即使規定了執行字符集和「C」語言環境中存在的擴展字符,我也沒有看到任何要求表示匹配。

+0

不錯的答案。要明確一點:如果他向'setlocale'添加了一個調用,那麼斷言可能會失敗,即使他的字符串完全在基本字符集內? – Nemo

+1

@Nemo如果用'C「以外的參數調用'setlocale()',是的。例如,在執行編碼與ASCII兼容的系統上,'setlocale(「en_US.EBCDIC」)'(假設這是受支持的語言環境,其含義明顯)會導致'c32rtomb()'產生EBCDIC字符串,而'std :: string窄'將保持ASCII編碼。 – bames53

5

的TR中的問題聯說

最多MB_CUR_MAX字節存儲。

其被定義(在C99)作爲

size_t類型的正整數表達式是一個字節在由當前語言環境中指定的擴展字符集多字節字符的最大數目

我相信這足以證明TR的意圖是產生由當前安裝的C語言環境定義的多字節字符:用於en_US.utf8的UTF-8,用於zh_CN.gb18030等的GB18030 c。

0

正如我測試的,在Linux/MacOSX中,c32rtomb將字符串從UTF-32轉換爲特定於語言環境的編碼。您可以使用nl_langinfo(CODESET)來獲取當前使用的編碼。

但是,libc默認使用「C」語言環境,它使用ISO-8859-1作爲編碼。要更改系統環境指定的編碼,通常是UTF-8但可能是其他編碼,請使用setlocale(LC_CTYPE,「」)。

在Windows中,VS2015 +,但是,c32rtomb總是轉換爲UTF-8。由於vcruntime不支持UTF-8語言環境(只支持傳統的ANSI/OEM語言環境),如果它遵循標準,則c32rtomb/c16rtomb將與wcrtomb完全相同,完全沒有用處。