2014-11-08 10 views
10

Rozważmy następujący przykładowy program:Jaka jest różnica między printf ("% s"), printf ("% ls"), wprintf ("% s") i wprintf ("% ls")?

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

Wyjście to jest:

1 narrow 
2 wide 

zastanawiam:

  1. dlaczego 3 & 4 nie drukować
  2. co różnice między 1 & 3 i 2 & 4.
  3. Czy robi to jakąś różnicę, jeśli narrowstr jest w utf8, a broadestr jest w utf16?
+1

Czy przeczytałeś dokumentacja? W szczególności z [cstdio] (http://www.cplusplus.com/reference/cstdio/)? –

+0

"widestr jest w utf16" oznacza, że ​​używasz systemu Windows (więcej systemów przyjaznych Unicode używa UTF-32 jako domyślnego dla szerokich ciągów znaków). Istnieje wiele tajemniczych obręczy do skakania, jeśli chcesz zrobić coś poza ASCII w systemie WIndows używając standardowego C++ lub C. Równie dobrze możesz się poddać i użyć WinAPI. – Cubbi

+0

NIE PODAWAJ DO GŁUPOŚCI MICROSOFT. Oszczędź sobie bólu i napisz własną bibliotekę ciągów. Z miłości do Boga NIE używaj makr w Windows i innych szaleństw, uwierz mi, to straszne, aw zamieszaniu pojawiają się wszelkiego rodzaju błędy. – Owl

Odpowiedz

0

Odpowiedzi na pytania 1 i 2 znajdują się w dokumentacji. Każdy dobry zestaw dokumentacji zrobi. Mówią, że cppreference jest bardzo dobry.

Jeśli chodzi o 3, standard językowy nie określa żadnego konkretnego kodowania dla ciągów lub jakiejkolwiek określonej wielkości wchar_t. Musisz zapoznać się z dokumentacją dotyczącą implementacji, a nie dla właściwego języka (choć pisanie kodu zależnego od implementacji rzadko jest wskazane).

5

Co trzeba zrobić:

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

Dlaczego? Ponieważ dla printf, % s mówi narrow-char-string. Dla wprintf, % ls mówi szeroko.

Ale dla wprintf, % s zakłada szerokie, % ls oznaczałoby szeroki sama. % hs oznaczałoby wąski (dla obu). Dla printf, % s, w ten sposób po prostu oznaczać % hs

na VC++/Windows, %S (kapitał S), by odwrócić ten efekt. W związku z tym dla printf("%S") oznaczałoby to szerokie, a wprintf("%S") oznaczałoby wąskie. Jest to przydatne dla _tprintf.

+0

To też niczego nie drukuje. [link] (http://ideone.com/ZCiDb1) –

+0

Trzymaj się! Dlaczego nawet nie drukuje liczb? Czy sprawdziłeś, czy wprintf działa? – Ajay

5

Pamiętaj, że używasz strumieni C. Strumienie C mają specjalną jakość zwaną "orientacją". Strumień jest albo nieorientowany, szeroki, albo wąski. Orientacja jest określana przez pierwsze wyjście wykonane do żadnego konkretnego strumienia (patrz http://en.cppreference.com/w/cpp/io/c na podsumowanie CI strumieni/O)

W twoim przypadku, stdout zaczyna się niezorientowanych i wykonując pierwszy printf, jesteś ustawienie go wąski . Po zawężeniu utknął w wąskim miejscu i nie powiodło się wprintf (sprawdź kod powrotu!). Jedynym sposobem na zmianę strumienia C jest freopen, który nie działa ze stdout. Właśnie dlatego 3 i 4 nie zostały wydrukowane.

Różnice między 1 a 3 są takie, że 1 jest wąską funkcją wyjściową, która wykorzystuje specyfikator konwersji wąskiego łańcucha% s: odczytuje bajty z tablicy znaków i wysyła bajty do strumienia bajtów.3 jest szeroką funkcją wyjściową z wąskim specyfikatorem konwersji łańcuchów% s: najpierw odczytuje bajty z tablicy znaków i mbtowc s je do wchar_t s, a następnie wysyła wchar_t s do szerokiego strumienia, który następnie wctomb s je do bajtów lub sekwencji wielobajtowych które następnie są wypychane do standardowego standardu z write Wreszcie, jeśli najszerszy jest w utf16, musisz używać systemu Windows, a wszystkie zakłady są wyłączone; na tej platformie jest bardzo niewiele wsparcia dla niczego poza ASCII. Równie dobrze możesz się poddać i użyć WinAPI (możesz uzyskać standardowe C++ 11 dla niektórych rzeczy w Unicode, a nawet zrobić to wyjście C z magicznymi słowami _setmode(_fileno(stdout), _O_U16TEXT);, które zostały omówione wystarczająco dużo razy)

Powiązane problemy