2012-10-24 7 views
21

Le funzioni c32rtomb e mbrtoc32 da <cuchar>/<uchar.h> sono descritti nella C Unicode TR (draft) come eseguire conversioni tra UTF-32 e "caratteri multibyte".Quale codifica viene convertita in c32rtomb?

(...) Se s non è un puntatore nullo , la funzione c32rtomb determina il numero di byte necessari per rappresentare carattere multibyte corrispondente al carattere esteso in c32 (comprese le sequenze di spostamento) e memorizza la rappresentazione del carattere multibyte in la matrice il cui primo elemento è puntato da s. (...)

Che cos'è questa "rappresentazione di carattere multibyte"? Sono davvero interessato al comportamento del seguente programma:

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

è l'affermazione in esso garantito per tenere ?


Lavorare sotto l'ipotesi che __STDC_UTF_32__ è definito.

risposta

10

Affinché l'asserzione venga mantenuta valida, è necessario che la codifica multibyte utilizzata da c32rtomb() sia uguale alla codifica utilizzata per i valori letterali stringa, almeno per quanto riguarda i caratteri effettivamente utilizzati nella stringa.

C99 7.11.1.1/2 specifica che setlocale() con la categoria LC_CTYPE influisce sul comportamento delle funzioni di gestione dei caratteri e sulle funzioni di carattere multibyte e wide. Non vedo alcun riconoscimento esplicito che l'effetto sia quello di impostare le codifiche di carattere multibyte e wide usate, tuttavia questo è l'intento.

Quindi la codifica multibyte utilizzata da c32rtomb() è la codifica multibyte dalla locale predefinita "C".

C++ 11 2.14.3/2 specifica che la codifica di esecuzione, la codifica di esecuzione ampia, UTF-16 e UTF-32 vengono utilizzate per i caratteri letterali e stringhe corrispondenti.Pertanto, std::string narrow utilizza la codifica di esecuzione per rappresentare tale stringa.

Quindi la codifica locale "C" di questa stringa è la stessa della codifica di esecuzione di questa stringa?

C99 7.11.1.1/3 specifica che l'impostazione locale "C" fornisce "l'ambiente minimo" per la traduzione C. Un tale ambiente includerebbe non solo i set di caratteri, ma anche i codici di caratteri specifici usati. Quindi credo che questo significhi non solo che la localizzazione "C" deve supportare i caratteri richiesti nella traduzione (cioè il set di caratteri di base), ma in aggiunta che quei caratteri nella locale "C" devono usare gli stessi codici di caratteri.

Tutti i caratteri nelle stringhe sono membri del set di caratteri di base, e quindi convertendo il char32_t rappresentazione alla rappresentazione locale char "C" deve produrre la stessa sequenza di valori come il compilatore produce per la stringa char letterale ; l'affermazione deve essere vera.

Non vedo alcun suggerimento che qualcosa oltre il set di caratteri di base sia supportato in modo compatibile tra la codifica di esecuzione e le impostazioni locali "C", quindi se la stringa letterale utilizza caratteri esterni al set di caratteri di base allora non sarebbe alcuna garanzia che l'affermazione sarebbe valida. Anche stipulando i caratteri estesi che esistono sia nel set di caratteri di esecuzione sia nella localizzazione "C", non vedo alcun requisito che le rappresentazioni corrispondano l'una con l'altra.

+0

Risposta piacevole. Giusto per essere chiari: se aggiunge una chiamata a 'setlocale', l'asserzione potrebbe fallire, anche se le sue stringhe sono interamente nel set di caratteri di base? – Nemo

+1

@Nemo Se 'setlocale()' è stato chiamato con un argomento diverso da '" C "', sì. Per esempio 'setlocale (" en_US.EBCDIC ")' (supponendo che sia un locale supportato con il significato ovvio) su un sistema dove la codifica dell'esecuzione è compatibile ASCII causerebbe 'c32rtomb()' per produrre stringhe EBCDIC mentre 'std :: string narrow' resterebbe codificato ASCII. – bames53

5

Il TR collegato alla questione dice

Al massimo MB_CUR_MAX byte vengono memorizzati.

definito (in C99) come

un'espressione intero positivo con il tipo size_t che è il numero massimo di byte in un carattere multibyte per il set di caratteri esteso specificato dal locale corrente

Credo che questa sia una prova sufficiente del fatto che l'intento del TR era di produrre i caratteri multibyte come definito dal locale C attualmente installato: UTF-8 per en_US.utf8, GB18030 per zh_CN.gb18030, et

0

Come ho provato, in Linux/MacOSX, c32rtomb converte le stringhe da UTF-32 alle codifiche specifiche della locale. È possibile utilizzare nl_langinfo (CODESET) per ottenere la codifica attualmente utilizzata.

Tuttavia, libc utilizza le impostazioni internazionali "C" per impostazione predefinita, che utilizza ISO-8859-1 come codifica. Per modificare la codifica a cui specifica l'ambiente di sistema, in genere UTF-8 ma potrebbe essere altri, utilizzare setlocale (LC_CTYPE, "").

In Windows, VS2015 +, tuttavia, c32rtomb viene sempre convertito in UTF-8. Poiché vcruntime non supporta le versioni locali di UTF-8 (sono supportate solo versioni locali ANSI/OEM legacy), se seguisse lo standard, c32rtomb/c16rtomb sarebbe del tutto identico a wcrtomb, e del tutto inutile.

Problemi correlati