5 votes

Pourquoi printf peut afficher des caractères non ASCII lorsque la locale "C" est utilisée ?

Note : Je demande un comportement défini par l'implémentation qui est sur Microsoft Visual C++ 2008 (peut-être le même sur 2005+). OS : installation chinoise simplifiée de Win7.

Ça me surprend quand j'effectue des entrées/sorties non ASCII avec printf . Par exemple

   // This won't be necessary as it's the system default code page.
   //system("chcp 936");

   // NULL to show current locale, which is "C"
   printf ("%s\n", setlocale(LC_ALL, NULL));
   printf ("\n");
   printf ("%s\n", setlocale(LC_ALL, "English"));
   printf ("\n");

Sortie :

Active code page: 936
C

English_United States.1252
?D

L'empreinte mémoire dans le débogueur montre que "" est codé en deux octets : 0xD6 , 0xD0 qui est le point de code de ce caractère dans la page de code 936, pour le chinois simplifié. Il ne devrait pas se trouver dans la plage de codets de la page 936. "C" locale qui, le plus probable c'est 0x0 ~ 0x7F .

Pregunta:

Pourquoi le caractère s'affiche-t-il toujours correctement dans la locale "C" ? J'ai donc supposé que la locale n'avait pas d'influence sur l'affichage du caractère. printf ? Mais alors, je me demande pourquoi il ne s'affiche plus lorsqu'on passe en mode "English" locale, qui est également différente de 936 ? Intéressant ?

Edit :

J'ai redirigé la sortie standard vers un fichier et fait quelques tests. Il montre que, quelle que soit la locale choisie, le caractère correct "" est enregistré dans le fichier. Il suggère que setlocale() est lié à la façon dont la console affiche le caractère, ce qui contredit ma compréhension de son fonctionnement : printf met les octets/points de code dans le tampon d'entrée de la console, qui interprète ces octets à l'aide de sa propre page de code (ce que le chcp retours).

3voto

Dewfy Points 11277

Le 936 est un codepage assez délicat, il autorise le caractère de 2 symboles (comme le fait l'UTF-8). Par exemple, le cyrillique (866) n'autorise pas les caractères à deux octets et son comportement sera le même que celui de l'"anglais".

Ainsi, lorsque vous utilisez la page de code default(936), elle sait comment traiter les caractères à deux symboles, alors que "English" traite les caractères à deux symboles. 0x0 ~ 0x7f seulement.

Permettez-moi également de répondre à la question de savoir pourquoi wprintf(L"") échoue. Il y a une grande différence entre une application console et une application Windows-window, elles utilisent des pages de code différentes. Voici les correspondances entre la console et Windows :

DOS   |   Windows
------+----------
850   |  1252
936   | 54936
866   |  1251

Donc, si vous voulez voir en console les symboles corrects, utilisez WideCharToMultiByte d'abord - qui fournit la conversion attendue pour permettre le travail en console en 936

3voto

James Holderness Points 15849

Le fait que la locale C imprime la chaîne de caractères exactement comme indiqué n'est pas surprenant. C'est ce à quoi je m'attendais. Ce qui est surprenant, c'est que les paramètres locaux anglais fassent quelque chose de différent.

Selon les Documentation sur les paramètres locaux sur MSDN le seul effet que la locale devrait avoir sur printf consiste à déterminer le caractère radix pour les valeurs numériques (c'est-à-dire le point décimal).

Je soupçonne peut-être qu'il s'agit d'un bogue dans le compilateur de Microsoft. Ou au moins, c'est un comportement non documenté.

Pour ce que cela vaut, sur mon compilateur (Borland), la locale n'a aucun effet sur la sortie de ces chaînes. Par contre, elle a un effet sur le radix.

0voto

Eric Z Points 7160

OK. Pour la locale "C" par défaut, CRT suppose que les caractères passés à printf n'ont pas besoin de conversion. Cela s'explique par le fait que les caractères ASCII font presque toujours partie du jeu de caractères de base du système d'exécution (partagé entre les différentes pages de code Windows). Lorsqu'il passe à "English", il suppose que l'entrée est encodée dans la page de code 1252, et essaie donc d'effectuer une conversion de "English" à "Chinese", qui est la locale utilisée par la console. Mais CRT ne trouve pas le caractère dans la page de code 1252. C'est pourquoi il sort un point d'interrogation.

Lorsqu'il est redirigé vers un fichier, le CRT le sait et n'effectue pas la conversion, car la page de code de la console n'est plus utilisée. Il transmet simplement les octets tels quels. La façon dont ces octets sont interprétés dépend du programme que vous utilisez (par exemple, si vous vous souciez de la nomenclature ou non) lorsque vous ouvrez le fichier.

Reportez-vous à ce lien du forum MSDN : Pourquoi printf peut afficher des caractères non ASCII lorsque la locale "C" est utilisée ?

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X