2012-10-24 12 views
21

Funkcje c32rtomb i mbrtoc32 z <cuchar>/<uchar.h> opisano C Unicode tR (draft), jak wykonywanie konwersji między UTF-32 i "postaci wielobajtowych".Jakie kodowanie jest konwertowane na c32rtomb?

(...) Jeśli s nie jest zerowy wskaźnik, funkcja c32rtomb określa liczbę bajtów potrzebnych do reprezentowania znak wielobajtowy, która odpowiada szerokości znaku danego przez c32 (włącznie z sekwencjami zmianowych) i przechowuje wielobajtową reprezentację znaków w tablicy, której pierwszy element jest wskazywany przez s. (...)

Co to jest "reprezentacja znaków wielobajtowych"? Właściwie jestem zainteresowany w zachowaniu następującego programu:

#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); 
} 

Czy twierdzenie w to gwarantowane trzymać ?


Praca przy założeniu, że __STDC_UTF_32__ jest zdefiniowana.

Odpowiedz

10

Aby zagwarantować zachowanie twierdzenia, konieczne jest, aby kodowanie wielobajtowe używane przez c32rtomb() było takie samo jak kodowanie używane w literałach ciągów, co najmniej tak daleko jak znaki faktycznie używane w ciągu znaków.

C99 7.11.1.1/2 określa, że ​​setlocale() z kategorią LC_CTYPE wpływa na zachowanie funkcji obsługi znaków oraz wielobajtowych i szerokich funkcji znakowych. Nie widzę wyraźnego potwierdzenia, że ​​efektem jest ustawienie kodowania wielobajtowego i szerokiego, ale jest to zamierzone.

Kodowanie wielobajtowe używane przez c32rtomb() jest kodowaniem wielobajtowym z domyślnego ustawienia narodowego "C".

C++ 11 2.14.3/2 określa, że ​​kodowanie wykonania, kodowanie szerokiego wykonywania, UTF-16 i UTF-32 są używane dla odpowiedniego znaku i literałów łańcuchowych.Dlatego std::string narrow używa kodowania wykonania do reprezentowania tego ciągu.

Czy kodowanie regionalne "C" tego łańcucha jest takie samo jak kodowanie wykonawcze tego łańcucha?

C99 7.11.1.1/3 określa, że ​​ustawienie "C" zapewnia "minimalne środowisko" dla tłumaczenia C. Takie środowisko obejmowałoby nie tylko zestawy znaków, ale także specyficzne kody znaków. Uważam więc, że oznacza to nie tylko, że ustawienia regionalne "C" muszą obsługiwać znaki wymagane w tłumaczeniu (tzn. Podstawowy zestaw znaków), ale dodatkowo, że te znaki w ustawieniach narodowych "C" muszą używać tych samych kodów znaków.

Wszystkie postacie w swoich napisowych należą do podstawowego zestawu znaków, a więc przekształcenie reprezentacji char32_t do „C” reprezentacji char locale musi produkować taką samą sekwencję wartości jak kompilator produkuje dla struny char dosłownym ; twierdzenie musi być prawdziwe.

Nie widzę żadnej sugestii, że cokolwiek poza podstawowym zestawem znaków jest obsługiwane w kompatybilny sposób między kodowaniem wykonawczym a locale "C", więc jeśli twój ciąg literału używał dowolnych znaków spoza podstawowego zestawu znaków, to tam nie byłaby żadną gwarancją, która miałaby obowiązywać. Nawet przewidując rozszerzone znaki, które istnieją zarówno w zestawie znaków wykonawczych, jak i locale "C", nie widzę żadnego wymogu, aby reprezentacje pasowały do ​​siebie.

+0

Dobra odpowiedź. Dla jasności: jeśli doda wezwanie do 'setlocale', to twierdzenie może się nie powieść, nawet jeśli jego ciągi są całkowicie w podstawowym zestawie znaków? – Nemo

+1

@Nemo Jeśli 'setlocale()' zostało wywołane z argumentem innym niż '" C "', tak. Na przykład 'setlocale (" en_US.EBCDIC ")' (przyjmując, że jest to obsługiwana lokalizacja z oczywistym znaczeniem) w systemie, w którym kodowanie wykonania jest zgodne z ASCII, powodowałoby, że 'c32rtomb()' tworzyłby łańcuchy EBCDIC, podczas gdy 'std :: string narrow' pozostanie zakodowany w ASCII. – bames53

5

TR połączone w pytaniu mówi

Co najwyżej MB_CUR_MAX bajty są przechowywane.

która jest zdefiniowana (w C99) jako

dodatnią ekspresji całkowitą o rodzaju size_t to jest maksymalnej liczby bajtów w wielobajtowym znak dla rozszerzonego zestawu znaków określonego przez z lokalizacją

Sądzę, że jest to wystarczający dowód, że intencją TR było wyprodukowanie znaków wielobajtowych zgodnie z definicją aktualnie zainstalowanego języka C: UTF-8 dla en_US.utf8, GB18030 dla zh_CN.gb18030, et c.

0

Jak przetestowałem, w Linux/MacOSX, c32rtomb konwertuje ciągi z UTF-32 na kodowanie specyficzne dla ustawień narodowych. Możesz użyć nl_langinfo (CODESET), aby uzyskać aktualnie używane kodowanie.

Jednak libc domyślnie używa ustawień regionalnych "C", które używa kodowania w ISO-8859-1. Aby zmienić kodowanie do środowiska systemowego, zwykle UTF-8, ale może być inne, użyj setlocale (LC_CTYPE, "").

W systemie Windows, VS2015 +, jednak c32rtomb zawsze konwertuje na UTF-8. Ponieważ vcruntime nie obsługuje ustawień narodowych UTF-8 (obsługiwane są tylko starsze wersje językowe ANSI/OEM), jeśli jest zgodny ze standardem, c32rtomb/c16rtomb będzie całkowicie identyczny z wcrtomb i nie będzie w ogóle używany.

Powiązane problemy