2011-09-21 15 views
7

Próbuję wydrukować ciąg wchar_t *. Kod spadnie poniżej:char vs wchar_t

#include <stdio.h> 
#include <string.h> 
#include <wchar.h> 

char *ascii_ = "中日友好"; //line-1 
wchar_t *wchar_ = L"中日友好"; //line-2 

int main() 
{ 
    printf("ascii_: %s\n", ascii_); //line-3 
    wprintf(L"wchar_: %s\n", wchar_); //line-4 
    return 0; 
} 

//Output 
ascii_: 中日友好 

Pytanie:

  1. Widocznie nie powinien przypisać znaków CJK do char * wskaźnik w wierszu-1, ale po prostu to zrobił, a wyjście z linii -3 jest poprawne, więc dlaczego? W jaki sposób printf() w linii-3 może podać mi znaki spoza ASC? Czy w jakiś sposób zna kodowanie?

  2. Zakładam, że kod w linii 2 i linii 4 jest poprawny, ale dlaczego nie otrzymałem żadnego wyniku linii 4?

+0

Jakiego kompilatora używasz? GCC domyślnie korzysta z Utf-8 o większości platform. Wydaje mi się, że mam problem z kodowaniem. – cyco130

+0

@ cyco130, tak, gcc – Alcott

Odpowiedz

8

Po pierwsze, zazwyczaj nie jest dobrym pomysłem użycie znaków non-ascii w kodzie źródłowym. Prawdopodobnie dzieje się tak, że chińskie znaki są kodowane jako UTF-8, który działa z ascii.

Teraz, dlaczego wprintf() nie działa. Ma to związek z orientacją strumienia. Każdy strumień może być ustawiony tylko na normalny lub szeroki. Raz ustawiony, nie można go zmienić. Jest ustawiany przy pierwszym użyciu. (który jest ascii ze względu na printf). Po tym czasie wprintf nie będzie działał z powodu nieprawidłowej orientacji.

Innymi słowy, po użyciu printf() należy nadal używać printf(). Podobnie, jeśli zaczynasz od wprintf(), musisz nadal używać wprintf().

Nie można wymieszać printf() i wprintf(). (Z wyjątkiem Windows)

EDIT:

Aby odpowiedzieć na pytanie, dlaczego linia wprintf nie działa nawet sama. Jest tak prawdopodobnie dlatego, że kod jest kompilowany w taki sposób, że format UTF-8 z 中日友好 jest przechowywany w wchar_. Jednak kod wchar_t wymaga 4-bajtowego kodowania Unicode. (2 bajty w Windows)

Więc tam dwie opcje, które mogę myśleć:

  1. Nie przejmuj się wchar_t, i po prostu trzymać się z multi-byte char ów. Jest to prosty sposób, ale może się zepsuć, jeśli system użytkownika nie jest ustawiony na chińskie ustawienia narodowe.
  2. Użyj wchar_t, ale będziesz musiał kodować chińskie znaki za pomocą sekwencji unikowych Unicode. To oczywiście spowoduje, że nie będzie można go odczytać w kodzie źródłowym, ale będzie działać na każdym komputerze, który może drukować chińskie czcionki znaków, niezależnie od ustawień regionalnych.
+0

jeśli używasz unqode escape seq, muszę dowiedzieć się każdego chińskiego słowa seq, prawda? To będzie dużo pracy do wykonania: P – Alcott

+1

Prawidłowo. Jednak jestem pewien, że jest to dość powszechne, gdy można znaleźć narzędzie online, które można po prostu skopiować i wkleić chiński tekst, a to da ci sekwencję unikową Unicode. Aby zachować czytelność kodu, możesz zachować aktualny tekst w języku chińskim obok sekwencji wyjątków jako komentarz. – Mysticial

+0

dzięki Mysticial – Alcott

6

Linia 1 nie jest ascii, jest to kodowanie wielobajtowe używane przez kompilator podczas kompilacji. Na nowoczesnych systemach, które są prawdopodobnie UTF-8. printf nie zna kodowania. To tylko wysyłanie bajtów na standardowe wyjście i dopóki kodowanie się zgadza, wszystko jest w porządku.

Jednym z problemów, o którym należy pamiętać, jest to, że linie 3 i 4 razem wywołują niezdefiniowane zachowanie. Nie można mieszać znaków i znaków o szerokim zakresie na tym samym FILE (stdout).Po pierwszej operacji, FILE ma "orientację" (bajtową lub szeroką), a następnie każda próba wykonania operacji o przeciwnej orientacji prowadzi do UB.

+0

Komentuję printf(), mam trochę danych wyjściowych, ale nie chińskie znaki. Czemu? – Alcott

+0

Prawdopodobnie kodowanie lokalizacji jest nieprawidłowe. –

+0

kodowanie locale? Jak to naprawić? – Alcott

1

Pomijasz jeden krok i dlatego myślisz niewłaściwie.

Masz plik C na dysku, zawierający bajty. Masz ciąg "ASCII" i szeroki ciąg znaków.

Łańcuch ASCII pobiera bajty dokładnie tak, jak w linii 1 i wysyła je. Działa tak długo, jak kodowanie strony użytkownika jest takie samo, jak kodowanie po stronie programisty.

Szeroki ciąg najpierw dekoduje podane bajty w kodeków unikodowych i zapisanych w programie - może to pójdzie źle po twojej stronie. Na wyjściu są one kodowane ponownie zgodnie z kodowaniem po stronie użytkownika. Gwarantuje to, że te znaki są emitowane tak, jak są przeznaczone, a nie w taki sposób, w jaki zostały wprowadzone.

Albo twój kompilator przyjmuje złe kodowanie, albo twój wyjściowy terminal jest źle ustawiony.