9
votes

L'entrée / sortie de caractères large en C est-elle toujours lue de / écriture sur le codage correct (par défaut système) correct?

Je suis principalement intéressé par les systèmes de type UNIX (par exemple, POSIX portable) comme il semble que Windows fait des choses étranges pour des caractères larges.

Faites les fonctions de caractères de lecture et d'écriture d'écriture (comme getwchar () et putwchar () ) toujours "faire la bonne chose", par exemple en lecture de UTF-8 et écrire à UTF-8 quand c'est la locale définie, ou dois-je appeler manuellement wcrtomb () et imprimer la chaîne en utilisant par exemple fputts () ? Sur mon système (opensuse 12.3) où $ lang est défini sur EN_GB.UTF-8 Ils semblent faire la bonne chose (inspectant la sortie que je vois ce qui ressemble à UTF -8 Même si des chaînes ont été stockées avec WCHAR_T et écrit à l'aide des fonctions de caractère larges).

Cependant, je ne suis pas sûr si cela est garanti. Par exemple, CProgramming.com stipule que:

[caractères larges] ne doit pas être utilisé pour la sortie, puisque zéro parasite octets et autres caractères Low-ASCII avec des significations communes (telles que '/' et '\ n') sera probablement saupoudré dans les données.

qui semble indiquer que la sortie des caractères larges (en utilisant probablement les fonctions de sortie de caractères larges) peut faire des ravages.

Puisque la norme C ne semble pas mentionner le codage du tout, je n'ai vraiment aucune idée de qui / quand / comment le codage est appliqué lors de l'utilisation de wchar_t. Donc, ma question est essentiellement si la lecture, l'écriture et l'utilisation de caractères larges exclusivement sont une bonne chose à faire lorsque mon application n'a pas besoin de savoir sur le codage utilisé. Je n'ai besoin que de longueurs de chaîne et de largeurs de la console ( wcswidth () ), donc à moi en utilisant WCHAR_T partout lors de la gestion du texte semble idéal.


0 commentaires

3 Réponses :


-1
votes

n'utilise pas fputts avec quelque chose d'autre que ASCII.

Si vous souhaitez écrire, disons UTF8, utilisez une fonction qui renvoie la taille réelle utilisée par la chaîne UTF8 et utilisez Fwrite pour écrire le bon nombre d'octets, sans vous soucier de vicieux ' \ 0 'à l'intérieur de la chaîne.


7 commentaires

Bienvenue dans le débordement de pile. FLCTS () sortira une chaîne d'octets vers le premier octet zéro. UTF-8 ne contient qu'une seule valeur de caractère avec un octet zéro, et c'est u + 0000 (codé comme '\ 0' dans utf-8). Donc, fputts () ne manipule pas une chaîne UTF-8 terminée null. En effet, l'un des mérites de l'UTF-8 est qu'un programme Nazze qui n'est pas au courant de l'UTF-8 peut souvent gérer les cordes correctement. (Pas toujours - il y a beaucoup de façons de causer des problèmes; mais souvent ...) aussi, fputts () convient aux codes de code mono-octets tels que ISO 8859-1 ou 8859-15 (8859 -2, ...). La limiter à ASCII est injustifiable.


Bonjour, il ne compile pas comme UTF8 complet. Il utilise la chaîne UTF8 en source compilée ASCII.


Et FLCTS échouera car UTF8 ne sont pas un octet codé des chaînes codées.


Mieux que cela devrait utiliser WCHAR et FUPTWS (const wchar_t * restreindre, fichier * restreindre);


Fallts () Ne manquera pas simplement parce que UTF8 est un jeu de code multi-octets. En effet, l'un des objectifs de la conception de l'UTF8 était de laisser les programmes naïfs qui ignorent l'UTF8 le traitent toujours avec succès. Votre affirmation selon laquelle FLCTS () est seulement bon pour ASCII est flagrante de manière flagrante, même en prenant une interprétation de bienfaisance que vous voulez dire "un code mono-octet défini en fonction de l'ASCII, tel que 8859-1". Notez que UTF8 est un ensemble de code multi-octets (ou codage de caractères), pas un qui utilise des caractères larges; Vous ne manipuleriez pas UTF8 avec des fonctions de caractère large. UTF16 et UTF32 sont des représentations de caractère large de Unicode.


Maintenant, si vous essayez de discuter que vous ne pouvez pas utiliser fputts () pour sortir une chaîne de caractères largeur, alors je suis d'accord avec vous, mais ce n'est pas ce que votre réponse dit du tout. Votre réponse évite largement de répondre à la question actuelle, en fait.


Ma réponse dit ce qu'elle dit: l'écriture échouera. Qui signifie que le comportement ne sera pas ce qui a assisté. Pourquoi: à cause du codage. De plus, je ne suis pas celui qui se dispute là-bas. Tu es. \ 0 est zéro. Beaucoup de personnages ancrochés multi-octets auront un seul 0 dans un octet qui ne signifie plus d'écoute avec les fnstes.



9
votes

Tant que la locale est définie correctement, il ne devrait pas y avoir de problèmes de traitement des fichiers UTF-8 sur un système à l'aide de UTF-8, à l'aide des fonctions de grande taille. Ils seront capables d'interpréter les choses correctement, c'est-à-dire qu'ils traiteront un caractère comme 1 à 4 octets si nécessaire (en entrée et en sortie). Vous pouvez le tester par quelque chose comme ceci:

char *stdtxt = "ASCII and UTF-8 €£¢";
wchar_t buf[100]; 
mbstowcs(buf, stdtxt, 20);

wprintf(L"%ls has %zu wide characters\n", buf, wcslen(buf));

Output:
ASCII and UTF-8 €£¢ has 19 wide characters


5 commentaires

"Pause" n'est pas tout à fait juste. La description devrait être "la chaîne occupe 7 octets", ce qui est précis. Qu'il contient seulement 3 caractères est également correct. Ceci est une différence de partie entre chaînes multi-octets ( mbs * fonctions) et chaînes de caractères ( wcs * fonctions). Cependant, c'est la nitpicking; Votre réponse principale va bien.


@Jonathanleffler - Je venais d'éditer pour traiter ce que j'ai dit comme vous l'avez écrit.


@Jonathanleffler - heh, ça va. Je l'ai rempli un peu.


@teppic: Merci pour les exemples, votre réponse était également très bonne.


Utilisez STRNLEN , pas SHLEN .



9
votes

Le texte pertinent régissant le comportement des fonctions de STDIO de nature large et leur relation avec les paramètres régionaux provenait de POSIX XSH 2.5.2 Orientation des flux et Règles de codage:

http://pubs.opengroup.org/onlinepubs/9699919799/fonctions/v2_chap02.html # tag_15_05_02

Fondamentalement, les fonctions STDIO de la grande caractéristique écrivent toujours dans l'encodage en vigueur (par la catégorie LC_CTYPE LC_CTYPE) au moment où le fichier le fichier devient grand-orienté; Cela signifie la première fois qu'une vaste fonction STDIO est appelée sur elle, ou Awide est utilisé pour définir l'orientation sur large. Ainsi, aussi longtemps qu'un LC_CTYPE LC_CTYPE correspondant à l'encodage "Système" souhaité (E.G. UTF-8) lorsque vous commencez à travailler avec le flux, tout devrait être bien.

Cependant, une considération importante que vous ne devriez pas négliger, c'est que vous ne devez pas Mélanger les octets et les opérations orientées larges sur le même fichier flux. Ne pas respecter cette règle n'est pas une erreur à déclarer; Il en résulte simplement comportement non défini . Comme une bonne affaire de code de bibliothèque assume stardr est orienté octet (et certains en font même la même hypothèse sur stdout ), je découragerais fortement jamais en utilisant des fonctions grandes orientées sur les flux standard. Si vous le faites, vous devez faire très attention à quelles fonctions de la bibliothèque que vous utilisez.

Vraiment, je ne peux penser à aucune raison d'utiliser des fonctions grandes orientées. Fprintf est parfaitement capable d'envoyer des chaînes de caractères larges aux flux de fichiers orientés par octets à l'aide du spécificateur % ls .


5 commentaires

Je suppose que l'utilisation de Putwchar (WC) donne une meilleure performance que de devoir utiliser Printf ("% LC", WC), mais pour mon utilisation actuelle que la différence de performance n'est probablement pas importante. Mais juste pour être clair, fixer STDOUT à une orientation large ne sera problématique que si les fonctions de la bibliothèque écrivent réellement sur stdout, correct?


@QuanTrumboredom: oui. stdout commence sans orientation, mais une fois que vous écrivez à l'aide d'une fonction de caractère large, il est défini sur large et que vous ne devez plus utiliser les fonctions d'octet dessus ( starr reste non affecté ). Je ne peux penser à aucune fonction de bibliothèque standard qui utilisera stdout , mais les bibliothèques externes pourraient.


@teppic: OK, dans ma demande, tout ce que l'écriture de STDOUT serait un bogue de toute façon, et j'ai mesuré la performance de la moitié lors de l'utilisation de Printf ("% LC", WC) Versus putwchar (WC), donc je pense que je pense que je pense que je pense que Large sortie sur stdout. Merci de créer un lien avec la norme correspondante dans votre réponse :-)


@Quantubordom - c'était R .. :) j'ai mis à jour ma réponse avec votre question pour l'achèvement.


@teppic: ah, je n'ai pas remarqué. Merci à vous deux :-)