Posts tagged ‘Unicode’

Z unikodem lub bez

2008-01-11 18:10

Unicode to ciekawy wynalazek. Zamiast stosować wymyślne sposoby na “przełączanie” sposobu interpretowania zwykłych 8-bitowych znaków, ktoś mądry wymyślił po prostu, że obecnie nie ma większych przeciwwskazań, aby zwykły tekst zajmował dwa razy więcej miejsca niż dotychczas. Powstał więc standard UTF-16, w którym stron kodowych nie ma, a każdy znak jest zapisany za pomocą jednego z 65536 kodów.
Ale jak to zwykle bywa z rozwiązaniami, które mają rozwiązywać istniejące problemy, Unicode natychmiast stworzył swoje własne :) Oprócz tego, że założone 16 bitów szybko okazało się za małe (stąd istnienie także UTF-32), powstał też szereg kłopotów praktycznych. Jednym z nich jest choćby to, że żyjemy w okresie przejściowym (który zresztą trwa już wybitnie długo) i że w użyciu jest zarówno unikod, jak i zwykłe ANSI. A na pierwszy rzut oka (ludzkiego i programowego) tekst jest po prostu ciągiem bajtów i bez zewnętrznych wskazówek nie jest możliwe określenie w stu procentach, czy został on zapisany w ANSI, UTF-8, UTF-16 czy UTF-32. Co więcej, znaki Unicode są oczywiście liczbami, a ponieważ zasadniczo zajmują one więcej niż jeden bajt, pojawia się problem z ustaleniem właściwej kolejności tych bajtów (little-endian lub big-endian).
Oba te problemy ma rozwiązywać tzw. znacznik porządku bajtów (Byte Order Mark), ale oczywiście jak większość dobrych praktyk, także i jego umieszczanie na początku dokumentów nie jest zbyt popularne :)

Z programistycznego punktu widzenia sprawa nie wygląda aczkolwiek aż tak źle i w większości przypadków jesteśmy w jednej z dwóch sytuacji. Pierwsza z nich to “nieświadome” korzystanie z unikodu (czy może raczej “szerokich”, dwubajtowych znaków), bo został o niego oparty używany przez nas język oraz platforma; najlepszymi przykładami są tu .NET i C# oraz Java.
Druga sytuacja to możliwość wyboru, z jakiego systemu będziemy korzystali. Bardzo dobre jest to, że prawie zawsze możemy zdecydować się na… oba, czyli potencjalne kompilowanie dwóch wersji: ANSI i Unicode. Pod Windows na przykład w programach pisanych w C++ wystarczy przestrzegać kilku prostych i dobrze znanych zasad:

  • Zamiast typów char (lub wchar_t) należy – wszędzie tam, gdzie chodzi nam o znaki – używać typu TCHAR, który w zależności od wersji zostanie zamieniony na jeden z tych dwóch.
  • Stałe napisowe należy wpisywać z użyciem makra TEXT (czyli TEXT("Coś") zamiast po prostu "Coś"), dzięki czemu zostaną one skompilowane jako łańcuchy ANSI lub Unicode.
  • Nie martwić się o to, jakich znaków używa systemowe API, bowiem wywołania funkcji systemowych zostaną przemapowane podczas kompilacji na właściwe wersje. Dotyczy to także niektórych bibliotek, jak chociażby DirectX.

Niestety, słowo ‘niektóre’ sytuuje się dość daleko od ‘wszystkie’ i dlatego ostatecznie nie jest tak różowo. Czołowe miejsce na liście “niewspółpracujących” zajmuje standardowa biblioteka C++. Z nią trzeba sobie poradzić we własnym zakresie.
Nie jest to aczkolwiek bardzo trudne, jako że każdy kompilator definiuje makro dla rozróżnienia wersji ANSI i Unicode. Visual C++ na przykład włącza w tym przypadku symbol _UNICODE, którego możemy użyć do stworzenia odpowiednich aliasów:

  1. namespace std
  2. {
  3.    #ifndef _UNICODE
  4.       // wersja ANSI
  5.       typedef string tstring;
  6.       #define cin tcin
  7.       #define cout tcout
  8.       typedef ostream tostream;
  9.       typedef istream tistream;
  10.       // ...
  11.    #else
  12.       // wersja Unicode
  13.       typedef wstring tstring;
  14.       // itd.
  15.    #endif
  16. }

Możemy je umieścić we własnym pliku nagłówkowym i dołączać we własnych projektach. Ponieważ jednak typów zależnych od znaków jest w STL całkiem sporo, można z powodzeniem użyć chociażby rozwiązania zamieszczonego na CodeProject, w razie potrzeby rozszerzając je o kolejne aliasy.

Tags: , ,
Author: Xion, posted under Programming » 2 comments
 


© 2023 Karol Kuczmarski "Xion". Layout by Urszulka. Powered by WordPress with QuickLaTeX.com.