2012-04-02 16 views
10

Jesteśmy szczególnie zainteresowani rozwojem systemów Windows i Linux i opracowaliśmy dwa różne podejścia, które wydają się mieć swoje zalety. Naturalny ciąg znaków Unicode w systemie Windows to UTF-16, a UTF-8 w systemie Linux.Wieloplatformowe C++: użyj natywnego kodowania lub standaryzacji na różnych platformach?

Nie możemy zdecydować, czy najlepszym podejściem:

  1. standaryzację na jednym z dwóch w całej naszej logiki aplikacji (i trwałych danych), i sprawiają, że inne platformy wykonaj odpowiednich przekształceń

  2. Skorzystaj z naturalnego formatu systemu operacyjnego dla logiki aplikacji (i tym samym nawiązywania połączeń z systemem operacyjnym), a konwertuj tylko w punkcie IPC i trwałości.

Wydaje mi się, że oboje są tak dobrzy, jak jeden drugiego.

+0

Jakie jest pytanie? – littleadv

+2

Co powinniśmy wybrać i dlaczego? Nie oczywiste? –

+0

"Co", a nie "co". Cholerny telefon –

Odpowiedz

6

i UTF-8 w systemie Linux.

Dotyczy to głównie współczesnego systemu Linux. Faktycznie kodowanie zależy od tego, z jakiego API lub biblioteki korzysta. Niektóre z nich zakodowane na stałe używają UTF-8. Ale niektórzy odczytywali zmienne środowiskowe LC_ALL, LC_CTYPE lub LANG, aby wykryć kodowanie do użycia (jak biblioteka Qt). Więc uważaj.

Nie możemy zdecydować, czy najlepszym podejściem

Jak zwykle to zależy.

Jeśli 90% kodu do czynienia z platformą dla konkretnego interfejsu API platformy w specyficzny sposób, oczywiście lepiej jest stosować konkretne ciągi platformy. Jako przykład - sterownik urządzenia lub natywna aplikacja iOS.

Jeśli 90% kodu jest złożona logika biznesowa, która jest dzielona na różnych platformach, oczywiście lepiej jest używać tego samego kodowania na wszystkich platformach. Jako przykład - klient czatu lub przeglądarka.

W drugim przypadku masz do wyboru:

  • Używaj krzyżowego biblioteki platformy, która zapewnia wsparcie łańcuchy (Qt, ICU, na przykład)
  • Stosować gołe wskaźniki (uważam std :: string jest „goły wskaźnik "zbyt")

Jeśli praca z ciągami jest istotną częścią aplikacji, dobrym wyborem jest wybranie ładnej biblioteki na ciągi. Na przykład Qt ma bardzo solidny zestaw klas obejmujący 99% typowych zadań. Niestety, nie mam doświadczenia z OIT, ale wygląda też bardzo ładnie.

Podczas korzystania niektóre biblioteki dla ciągów, które trzeba dbać o kodujący tylko podczas pracy z zewnętrznych bibliotek, platformy API lub wysyłając ciągi nad siatką (lub dysku). Na przykład, dużo kakao, C# lub Qt (wszystko ma solidne wsparcie łańcuchy) programiści bardzo mało wiedzą o kodujący dane (i to jest dobre, ponieważ mogą skupić się na ich głównym zadaniem).

Moje doświadczenie w pracy z ciągami to specyficzne dla małe, więc ja osobiście wolę czyste wskazówki. Kod, który z nich korzysta jest bardzo przenośny (w pewnym sensie może być łatwo ponownie użyty w innych projektach i platformach), ponieważ ma mniej zewnętrznych zależności. Jest to również bardzo proste i szybkie (ale jeden prawdopodobnie potrzebuje trochę doświadczenia i tła Unicode, aby to poczuć).

Zgadzam się, że podejście gołe wskaźniki nie jest dla każdego. Dobrze jest, gdy:

  • pracować z całych łańcuchów i dzielenie, wyszukiwanie, porównywanie jest rzadkim zadanie
  • Można używać tego samego kodowania we wszystkich komponentów i potrzebują jedynie konwersji przy użyciu interfejsu API platformy
  • Wszystko twoje obsługiwane platformy ma API:
    • przekonwertować z kodowaniem na który jest używany w API
    • przekonwertować z API do kodowania, który jest używany w kodzie
  • Wskaźniki nie jest problemem w zespole

Z mojego małego o określonego doświadczenia w rzeczywistości jest to bardzo częsty przypadek.

Podczas pracy z gołymi wskaźnikami dobrze jest wybrać kodowanie, które będzie używane w całym projekcie (lub we wszystkich projektach).

Z mojego punktu widzenia UTF-8 jest ostatecznym zwycięzcą. Jeśli nie można używać UTF-8 - używać łańcuchów bibliotekę lub platformy API dla strun - będzie to zaoszczędzić wiele czasu.

Zalety UTF-8:

  • pełni kompatybilny ASCII. Dowolny ciąg znaków ASCII to poprawny ciąg znaków UTF-8.
  • Biblioteka std C wspaniale działa z ciągami UTF-8. (*)
  • Std biblioteka C++ działa świetnie z UTF-8 (std :: string i friends). (*)
  • Legacy kod działa świetnie z UTF-8.
  • Dość każda platforma obsługuje UTF-8.
  • Debugowanie jest DUŻO łatwiejsze dzięki UTF-8 (ponieważ jest kompatybilny z ASCII).
  • Brak bałaganu Little-Endian/Big-Endian.
  • Nie złapiesz klasycznego błędu "O, UTF-16 nie zawsze jest 2 bajty?".

(*) Do musisz leksykalnych porównać je przekształcić sprawę (TOUPPER/TOLOWER), zmienić formę normalizacji lub coś podobnego - jeśli nie - używać łańcuchów biblioteka lub platforma API.

Wada jest wątpliwa:

  • mniej zwarta dla Chińczyków (i innych symboli z dużą liczbą punktów code) niż UTF-16.
  • Trudniej (trochę w rzeczywistości) do iteracji nad symbolami.

Polecam używanie UTF-8 jako wspólnego kodowania dla projektów, które nie używają żadnej biblioteki ciągów.

Ale kodowanie to nie jedyne pytanie, na które należy odpowiedzieć.

Istnieje coś takiego jak normalization. Mówiąc prościej, niektóre litery mogą być reprezentowane na kilka sposobów - jak jeden glif lub jak kombinacja różnych glifów. Powszechnym problemem jest to, że większość funkcji porównywania ciągów traktuje je jako różne symbole. Jeśli pracujesz nad projektem wieloplatformowym, wybór standardowej formy normalizacji jest właściwym posunięciem. Pozwoli to zaoszczędzić czas.

Na przykład, jeśli hasło użytkownika zawiera "ёёжиг", będzie ono różnie reprezentowane (zarówno w UTF-8, jak i UTF-16) po wprowadzeniu na Macu (które najczęściej używają Normendera Form D) i Windows (co najczęściej podoba się Formularz Normalizacji DO). Jeśli więc użytkownik zarejestrowany pod Windows z takim hasłem, będzie miał problem z zalogowaniem się na Macu.

Ponadto nie zaleca się używania wchar_t (lub używania go tylko w kodzie systemu Windows jako typu char UCS-2/UTF-16). Problem z wchar_t polega na tym, że nie ma z nim żadnego kodowania. To po prostu abstrakcyjny szeroki znak, który jest większy niż normalny znak (16 bitów w systemie Windows, 32 bity w większości * nix).

+0

Świetna odpowiedź, dzięki! –

0

Używam tego samego kodowania wewnętrznie i normalizuję dane w punkcie wejścia. Obejmuje to mniej kodu, mniej gotcha i pozwoli ci używać tej samej biblioteki między platformami do przetwarzania ciągów.

Używałbym unicode (utf-16), ponieważ jest łatwiejszy w obsłudze wewnętrznie i powinien działać lepiej ze względu na stałą długość każdej postaci. Format UTF-8 jest idealny do wyświetlania i przechowywania, ponieważ jest zgodny z łacińskim ascii, a unly używa 8 bitów dla znaków angielskich. Ale wewnątrz programu 16-bit jest łatwiejszy w obsłudze.

+0

Sugerujesz użycie UTF-8 do przechowywania? Wygląda jak najgorszy z obu światów. –

+0

Co jest najgorsze w utf8? Jest bardzo jasno określony. Jest bardzo kompaktowy (dla języków innych niż chiński). Jest bardzo w użyciu. –

+0

Nic nie jest najgorsze z utf-8. Najgorzej jest z utf-8 do przechowywania i utf-16 w pamięci na linux –

-1

Programowanie z UTF-8 jest trudne, ponieważ długości i przesunięcia są pomieszane. na przykład

std::string s = Something(); 
    std::cout << s.substr(0, 4); 

niekoniecznie znajduje pierwsze 4 znaki.

Użyłbym wszystkiego, co jest wchar_t. W systemie Windows, który będzie UTF-16. Na niektórych platformach * nix może to być UTF-32.

Podczas zapisywania do pliku, polecam konwersję do UTF-8. To często powoduje, że plik jest mniejszy i usuwa wszelkie zależności między platformami z powodu różnic w sizeof(wchar_t) lub kolejności bajtów.

+2

UTF-16 ma ten sam problem. Po zachodnich postaciach nie zauważysz. –

+0

To prawda, ale system Windows nie obsługuje funkcji UTF-32. Większość znaków utf-16 od> 0xFFFF to historyczne zestawy znaków, np. Starożytne greckie i kujonowe, ale jest kilka, które mogą być ważne. na przykład Rozszerzenia HAN CJK. Programista musi zdecydować, czy jest to ważne. Jeśli tak, to rozwiązanie staje się bardziej złożone. –

+0

Prawda. Zapomniałem, że Kanji mieści się w 16 bitach. –

0

C++ 11 udostępnia nowe typy ciągów: u16string i u32string. W zależności od tego, jakie wsparcie zapewniają wersje kompilatorów i oczekiwana długość życia, może być dobrym pomysłem, aby pozostać kompatybilnym z nimi.

Poza tym używanie biblioteki ICU jest prawdopodobnie najlepszym sposobem na uzyskanie zgodności między platformami.

Powiązane problemy