Genişletilmiş Karakterlere Giriş
Önceki VI. Oylum - Karakter Kümeleriyle Çalışma Sonraki
Genişletilmiş Karakterlere Giriş
Karakterlerle baytlar arasında 1:1 ilişki olan karakter kümeleri ile 1:2 den 1:4 oranlarına kadar ilişki olan karakter kümeleri arasındaki farkları aşacak çok çeşitli çözümler vardır. Bu bölümün devamında C kütüphanesinin işlevselliğini geliştirirken verilen tasarım kararlarını anlamaya yardımcı olacak bir kaç örneğe yer verilmiştir.
Önce dahili ve harici gösterimler arasında bir ayrım yapmalıyız. Dahili gösterim deyince bir yazılım tarafından bellekte tutulan metnin gösterimini anlıyoruz. Harici gösterim deyince ise bazı iletişim kanalları üzerinden aktarımda ya da bunlar üzerinde saklanacak metinlerin gösterimlerini anlıyoruz. Harici gösterime örnek vermek gerekirse, bir dizinde bulunan ve okunacak ya da çözümlenecek dosyaları gösterebiliriz.
Geleneksel olarak iki gösterim arasında bir fark yoktur. Tek baytlık dahili ve harici gösterim aynıdır ve eşit kullanılabilirliktedir. Bu kullanılabilirlik karakter kümeleri genişledikçe ve sayıları arttıkça azalır.
Dahili gösterimle ilgili aşılacak sorunlardan biri farklı karakter kümeleriyle harici olarak kodlanmış metinlerin elde edilmesidir. İki metni okuyup bazı ölçütleri kullanarak karşılaştıran bir yazılım varsayalım. Karşılaştırma sadece metinler dahili olarak bir ortak biçimde tutulabiliyorsa yapılabilir.
Böyle bir ortak biçim (= karakter kümesi) için sekiz bit elbette artık yeterli değildir. Öyleyse en küçük öğe büyütülmelidir: Artık geniş karakterler kullanılmalıdır. Karakter başına bir bayt yerine iki hatta dört bayt kullanılması sözkonusu olacaktır. (Üç, bellek adreslemesi açısından iyi bir değer değildir ve dört bayttan fazlası da gerekmemektedir).
Bu kılavuzun bazı bölümlerinde görüleceği gibi bellekte geniş karakterli metinlerle çalışabilen işlevlerle tamamen yeni bir işlev ailesi oluşturulmuştur. Bu tür geniş karakter gösterimleri için kullanılan karakter kümelerinin çoğu Unicode ve ISO 10646 (UCS olarak da bilinir. UCS: Universal Character Set - Evrensel Karakter Kümesi) kullanır. Unicode (yunikod diye okunur) bir 16 bitlik karakter kümesi olarak tasarlandı; ISO 10646 ise 31 bitlik dev bir kod uzayı olarak tasarlandı. Uygulamada her iki standart eşdeğerdir. Aynı karakter listesini ve aynı kod tablosunu kullanırlar. Fakat Unicode ek anlamsallık belirtir. Bu noktada, sadece ilk 0x10000 kodluk karakter (BMP: Basic Multilingual Plane - "Temel Çokdilli Seviye" olarak da bilinir) atanmıştır. Unicode ve ISO 10646 karakterleri için tanımlanmış kodlamalardan bazıları: UCS-2 16 bitliktir ve sadece BMP'deki karakterleri içerir. UCS-4 32 bitliktir ve Unicode ve ISO 10646 karakterlerini içerir. UTF-8 tek baytla gösterilen ASCII karakter kümesine ek olarak ASCII olmayan 2 ilâ 6 karakterlik dizilimlerle ifade edilen karakterleri içerir. Son olarak UTF-16, UCS-2'nin içerdiklerine ek olarak 0x10ffff e kadar BMP olmayan karakterleri içerir.
Geniş karakterleri göstermek için char türü yeterli değildir. Bu sebeple ISO C standardı bir geniş karakterli dizgenin bir karakterini tutmak için tasarlanmış yeni bir veri türünden bahseder. Benzerliği sağlamak için tek bir geniş karakter alan işlevlerde kullanılacak ve int türüne karşı düşen bir tür de vardır.
wchar_t
veri türü
Bu veri türü geniş karakterli dizgelerin temel türü olarak kullanılır. Başka bir deyişle, bu tür nesne dizileri, çokbaytlı karakterlerin char[] dizisine eşdeğerdir. Tür, stddef.h başlık dosyasında tanımlanmıştır.
ISO C90 standardı, wchar_t'den bahsederken gösterimi hakkında belirgin hiçbir şey söylemez. Sadece temel karakter kümesinin tüm elemanlarını saklama yeteneğinde olması gerektiğini belirtir. Diğer taraftan, gömülü sistemlere uyarlanabilirlik bakımından wchar_t türünün char olarak tanımlanması meşru olmalıdır.
Fakat GNU sistemleri için wchar_t daima 32 bit genişliktedir ve tüm USC-4 değerleri gösterebilme yeteneğine sahiptir, böylece ISO 10646'nın tümü kapsama dahil olur. Bazı Unix sistemlerinde wchar_t 16 bitlik olarak tanımlanır ve sadece Unicode'u kapsar. Bu tanımlama standart açısından geçerli olmakla birlikte ISO 10646 ve UCS-2 deki karakterlerinin tümü ile UTF-16'nın 16 biti aşan karakterlerini fiilen çoklu geniş karakter kodlaması olarak gösterebilir. Fakat çoklu geniş karakterli kodlamaya başvurulması wchar_t türünün kullanım amacıyla çelişir.
wint_t
veri türü
wint_t, tek bir geniş karakter içeren değişkenler ve parametreler için kullanılan bir veri türüdür. Normal char dizgeler kullanılırken isim olarak int türüne eşdeğer olan bu türün kullanılması önerilir. wchar_t ve wint_t türleri 32 bit genişlikte olduklarında çoğunlukla aynı gösterime sahiptir ancak, wchar_t char olarak tanımlanmışsa, parametre terfilerinden dolayı wint_t de int olarak tanımlanmalıdır.
Bu veri türü wchar.h başlık dosyasında tanımlanmış ve ISO C90'ın 1. düzeltmesinde bahsedilmiştir.
char veri türü için var olan makrolar gibi wchar_t türündeki bir nesnenin gösterebileceği azami ve asgari değerleri belirten makrolar da vardır.
wint_t WCHAR_MIN
makro
wint_t türünde bir nesne tarafından tutulabilecek en küçük değerdir.
Bu makro ISO C90 standardının 1. düzeltmesinde bulunur.
wint_t WCHAR_MAX
makro
wint_t türünde bir nesne tarafından tutulabilecek en büyük değerdir.
Bu makro ISO C90 standardının 1. düzeltmesinde bulunur.
Diğer bir geniş karakterlere özel değer EOF'a eşdeğerdir.
wint_t WEOF
makro
WEOF makrosu genişletilmiş karakter kümesindeki herhangi bir üyeden farklı olan wint_t türünde bir değer olarak değerlendirilir.
WEOF, EOF ile aynı değerde olmakla birlikte onun aksine negatif olmaması gereklidir. Başka bir deyişle, aşağıdaki küçük kod,
{
  int c;
  …
  while ((c = getc (fp)) < 0)
    …
}
geniş karakterler için doğrudan WEOF kullanılarak aşağıdaki gibi yazılır:
{
  wint_t c;
  …
  while ((c = wgetc (fp)) != WEOF)
    …
}
Bu makro wchar.h başlık dosyasında tanımlanmıştır ve ISO C90'ın 1. düzeltmesinde bulunur.
Bu dahili gösterimler saklama ve aktarım sırasına sorunlara yol açarlar. Çünkü her geniş karakter çok sayıda bayttan oluşur ve bunlar bayt sıralamasından etkilenirler. Makinelerin farklı bayt sıralamasına (endianess) sahip olmaları aynı verinin farklı değerlendirilmesine sebep olur. Bu bayt sıralaması ayrıca tamamı bayt temelli olan iletişim protokollerinden de etkilenir. Çoğunlukla gönderici geniş karakterleri baytlarına ayırmak konusunda bir karar vermek durumunda kalır. Bir son (ama en az önemli) husus da geniş karaktelerin, özelleştirilmiş tek baytlı karakter kümelerine göre daha fazla saklama alanı gerektirmesidir.
Yukarıdaki sebeplerden dolayı, dahili kodlama UCS-2 ya da UCS-4 ise çoğunlukla bir harici kodlama dahili kodlamadan farklı olur. Harici kodlama bayt temellidir ve ortama ve elde edilecek metine uygun olarak seçilebilir. Bu harici kodlama için farklı karakter kümeleri kullanılabilir. ASCII temelli tüm karakter kümeleri bir gereksinimi tamamen karşılar: Dosyasistemi bakımından yeterlilik (filesystem safe); yani '/' karakteri kodlama içinde sadece kendi olarak kullanılır. Bazı şeyler EBCDIC (Extended Binary Coded Decimal Interchange Code - Genişletilmiş İkilik kodlu Ondalık Değişim Kodu; IBM tarafından kullanılan bir karakter kümesi ailesidir) gibi karakter setleri için biraz farklıdır, ama işletim sistemi EBCDIC'i doğrudan anlayamıyorsa sistem çağrılarının parametrelerinde kullanmadan önce işletim sisteminin anlayabileceği kodlamaya dönüştürülmüş olmalıdır.
  • En basit karakter kümeleri tek baytlık karakter kümeleridir. Sadece 256 karakter içerebilir ve tüm dilleri kapsamak açısından yetersizdir. 8 bitlik karakter kümeleri ile çalışmak basittir. Daha sonra gösterileceği gibi bu doğru değildir, uygulamalar 8 bitlik karakter kümelerini kullanmaları gerektiği için kullanırlar.
  • ISO 2022 standardı, bir baytttan daha fazla baytla gösterilebilen karakterlerin olduğu genişletilmiş karakter kümeleri için bir mekanizma tanımlar. Bu, bir metni bir durumla ilişkilendirerek yapılır. Karakterler, metin içinde bulunabildikleri durumu değiştirmekte kullanılabilirler. Metindeki her bayt, her durum için farklı yorumlanmalıdır. Bir baytın kendisi olarak mı yoksa bir karakteri oluşturan çok sayıda bayttan biri olarak mı yorumlanacağı duruma bağlıdır.
    ISO 2022'nin çoğu kullanımlarında tanımlı karakter kümeleri bir sonraki karakterden fazlasını kapsayan durum değişikliklerine izin vermez. Bir karakterin bayt sırasının başlangıcı bulunduktan sonra metin doğru olalak yorumlanabildiğinden bu büyük yarar sağlar. Bu kuralı kullanan karakter kümelerine örnek olarak çeşitli EUC karakter kümeleri (Sun'ın işletim sistemlerinde kullanılan, EUC-JP, EUC-KR, EUC-TW ve EUC-CN) veya Shift_JIS (SJIS, bir Japonca kodlama) verilebilir.
    Ancak bir karakterden daha fazlası için geçerli olan ve diğer bir bayt sıralaması tarafından değiştirilen bir durumu kullanan karakter kümeleri de vardır. Bunlara örnek olarak ISO-2022-JP, ISO-2022-KR ve ISO-2022-CN verilebilir.
  • Latin alfabesini kullanan dillerin 8 bitlik karakter kümelerini düzeltmek için başlatılan çalışmalar ISO 6937 benzeri karakter kümeleri ile sonuçlandı. Burada ± gibi karakterleri oluşturan baytlar kendileri olarak bir çıktı üretmez: İstenen sonucu üretmek için birtakım karakterler birlikte kullanılır. Örneğin 0xc3 0xbc bayt sıralaması (8 bitlik ü karakterleri) ü karakterini oluşturur. ± karakterini elde etmek için ise 0xc2 0xb1 bayt sıralaması (8 bitlik ± karakterleri) kullanılır.
    ISO 6937 benzeri karakter kümeleri teletex gibi bazı gömülü sistemlerde kullanılır.
  • Dahili olarak kullanılan Unicode veya ISO 10646 metinlerini dönüştürmek yerine UCS-2/UCS-4 den farklı bir kodlamanın kullanılması çoğunlukla yeterli olur. Unicode ve ISO 10646 nın her ikisi de böyle bir kodlamayı belirtirler: UTF-8. Bu kodlama, 1 bayttan 6 bayta kadar uzunluklarda bayt dizgelerini 31 bit genişlikle, ISO 10646 daki tüm karakterleri gösterebilmektedir.
    ISO 10646'yı UTF-7 olarak kodlamak üzere bazı çalışmalarda yapılmıştır, ancak günümüzde kullanılması gereken tek kodlama UTF-8 dir. Aslında, UTF-8 gelecekte desteklenen tek harici kodlama olacaktır. Evrensel olarak kullanılabilirliği anlaşılmıştır. Tek olumsuz yanı, bazı dillerin karakterlerini oluştururken kullanılan bayt dizgelerinin uzunluğu bu diller için kullanılan özel kodlamalara göre daha büyük yer harcanmasına sebep olmasıdır. Ancak Unicode sıkıştırma şeması gibi yönemlerle bu sorunlar da giderilecektir.
Sona kalan soru şudur: Kullanılacak kodlama ya da karakter kümesi nasıl seçilecektir? Yanıt: Buna siz kendi kendinize karar veremezsiniz, bunu sistem geliştiricileri ile kullanıcıların çoğunluğunun yaptığı tercih belirler. Amaç birlikte çalışabilirlik olunca birinin kullandığını bir diğeri birlikte çalışabilmek için kullanacaktır. Bir kısıtlama yoksa seçim kullanıcıların ortak gereksinimlerine göre şekillenecektir. Başka bir deyişle örneğin, bir projenin sadece Rusya'da kullanılacağı düşünülüyorsa KOI8-R ya da benzeri bir karakter kümesi kullanmak gerekir. Ama aynı proje örneğin Yunanistan'da da kullanılabilecekse, karakter kümesi seçimi herkesin gereksinimlerine yanıt verebilecek şekilde seçilmelidir.
En geniş çözümü sağlayan, en genel karakter kümesi hangisi diye baktığımızda bunun ISO 10646 olduğunu görürüz. Harici kodlama olarak UTF-8 kullanılır ve geçmişte kendi dillerini kullanmakta sorunları olan kullanıcıların sorunları kalmaz.
Geniş karakter gösteriminin seçilmesi ile ilgili olarak son bir açıklama daha yapmak gerekir. Yukarıdaki açıklamaların ışığında doğal seçim Unicode veya ISO 10646 kullanmaktır dedik. Bu gerekli değildir ama en azından ISO C standardı tarafından cesaretlendiriliyoruz. Standart en azından __STDC_ISO_10646__ diye bir makro tanımlar ve bu makro sadece wchar_t türünün kodladığı ISO 10646 karakterlerinin kullanıldığı sistemlerde tanımlıdır. Bu sembolü tanımlamayarak geniş karakterli gösterimlerle ilgili kabuller yapılmasından kaçınılmalıdır. Yazılımcılar sadece C kütüphanesi tarafından sağlanan bu işlevleri kullandıklarında geniş karakterle ilgili olarak diğer sistemlerle bir uyumluluk sorunu yaşamazlar.
Önceki Üst Ana Başlık Sonraki
VI. Oylum - Karakter Kümeleriyle Çalışma Başlangıç Karakter Kümesi İşlevlerine Bakış
Bir Linux Kitaplığı Sayfası