web-dev-qa-db-fra.com

Quelle est la différence entre printf ("% s"), printf ("% ls"), wprintf ("% s") et wprintf ("% ls")?

Considérons cet exemple de programme:

#include <cstdio>
#include <cwchar>
#include <string>

int main()
{
    std::string narrowstr = "narrow";
    std::wstring widestr = L"wide";
    printf("1 %s \n", narrowstr.c_str());
    printf("2 %ls \n", widestr.c_str());
    wprintf(L"3 %s \n", narrowstr.c_str());
    wprintf(L"4 %ls \n", widestr.c_str());

   return 0;
}

Le résultat de ceci est:

1 narrow 
2 wide 

Je me demande:

  1. pourquoi 3 et 4 n'ont pas imprimé
  2. quelles sont les différences entre 1 et 3, et 2 et 4.
  3. cela fait-il une différence si narrowstr est dans utf8 et widestr dans utf16?
14
Display Name

Tu as besoin de faire:

wprintf(L"3 %hs \n", narrowstr.c_str());
wprintf(L"4 %s \n", widestr.c_str());

Pourquoi? Parce que pour printf,% s indique une chaîne de caractères étroite. Pour wprintf,% ls dit large.

Mais, pour wprintf,% s implique large,% ls voudrait dire large lui-même.% hs voudrait dire étroit (pour les deux). Pour printf,% s , signifierait simplement% hs

Sur VC++/Windows, %S (S majuscule) inverserait l'effet. Donc, pour printf("%S") cela signifierait large, et wprintf("%S") voudrait dire étroit. Ceci est utile pour _tprintf.

9
Ajay

Notez que vous utilisez des flux C. Les flux C ont une qualité très spéciale appelée "orientation". Un flux est soit non orienté, large ou étroit. L'orientation est déterminée par la première sortie d'un flux particulier (voir http://fr.cppreference.com/w/cpp/io/c pour un résumé des flux C I/O)

Dans votre cas, stdout commence sans être orienté et, en exécutant le premier printf, vous le définissez de manière étroite. Une fois étroit, il reste coincé étroit et wprintf échoue (vérifiez son code de retour!). Le seul moyen de changer un flux C est de le remplacer par freopen, ce qui ne fonctionne pas vraiment avec stdout. C'est pourquoi 3 et 4 n'ont pas imprimé.

La différence entre 1 et 3 est que 1 est une fonction de sortie étroite qui utilise le spécificateur de conversion de chaîne étroite% s: elle lit les octets du tableau de caractères et envoie les octets dans un flux d'octets. 3 est une fonction de sortie large avec un spécificateur de conversion de chaîne étroite% s: il lit d'abord les octets du tableau de caractères et les mbtowcs dans wchar_ts, puis envoie wchar_ts dans un flux large, qui est ensuite transmis par wctomb en octets ou en séquences de plusieurs octets dans la sortie standard avec un write

Enfin, si widestr est dans utf16, vous devez utiliser Windows et tous les paris sont désactivés; il y a très peu de support pour rien au-delà de ASCII sur cette plate-forme. Vous pouvez aussi bien céder et utiliser WinAPI (vous pouvez vous débrouiller avec le standard C++ 11 pour certaines choses Unicode, et même faire cette sortie C, avec les mots magiques _setmode(_fileno(stdout), _O_U16TEXT);, cela a été discuté suffisamment de fois)

5
Cubbi

Les réponses à 1 et 2 sont dans la question sont dans la documentation. Toute bonne documentation fera l'affaire. Ils disent cppreference est très bon.

En ce qui concerne 3, la norme de langue ne spécifie aucun codage particulier pour les chaînes, ni aucune taille particulière de wchar_t. Vous devez consulter la documentation relative à votre implémentation plutôt qu'à la langue proprement dite (bien que l'écriture de code dépendant de l'implémentation soit rarement recommandée).

0
n.m.