C ++ wchar_t ve wstrings'in "sorunu" nedir? Geniş karakterlere bazı alternatifler nelerdir?


87

C ++ topluluğundaki pek çok insanın (özellikle freenode üzerinde ## c ++) wstringsve wchar_tve bunların windows api'de kullanımına kızdığını gördüm . Tam olarak "yanlış" olan wchar_tve wstringuluslararasılaşmayı desteklemek istersem, geniş karakterlere alternatifler nelerdir?


1
Bunun için herhangi bir referans var mı?
Dani

14
Belki de bu harika başlık tüm sorularınızı cevaplayacaktır? stackoverflow.com/questions/402283/stdwstring-vs-stdstring
MrFox

15
Windows'ta gerçekten bir seçeneğiniz yok. Dahili API'leri, değişken uzunluklu UTF-8 ve UTF-16 kodlamalarının standartlaştırılmasından önceki dönemden beri makul olan UCS-2 için tasarlanmıştır. Ama şimdi UTF-16'yı destekledikleri için, her iki dünyanın da en kötüsüyle sonuçlandılar.
jamesdlin

12
utf8everywhere.org'da geniş karakterlerden kaçınmak için iyi bir neden tartışması var.
JoeG

5
@jamesdlin Kesinlikle bir seçeneğiniz var. nowide kitaplığı, dizeleri sadece API'lere geçerken dönüştürmek için uygun bir yol sağlar. Dizeleri olan API çağrıları genellikle düşük frekanstır, bu nedenle makul yol ad-hok'u dönüştürmek ve dosyaları ve dahili değişkenleri her zaman UTF-8'de bulundurmaktır.
Pavel Radzivilovsky

Yanıtlar:


115

Wchar_t nedir?

wchar_t, herhangi bir yerelin karakter kodlamasının, her wchar_t'nin tam olarak bir kod noktasını temsil ettiği bir wchar_t gösterimine dönüştürülebileceği şekilde tanımlanır:

Tür wchar_t, değerleri desteklenen yerel ayarlar (22.3.1) arasında belirtilen en büyük genişletilmiş karakter kümesinin tüm üyeleri için farklı kodları temsil edebilen farklı bir türdür.

                                                                               - C ++ [temel. Temel] 3.9.1 / 5

Bu , wchar_t'nin tüm yerel ayarlardan aynı anda herhangi bir karakteri temsil edecek kadar büyük olmasını gerektirmez. Yani, wchar_t için kullanılan kodlama yerel ayarlar arasında farklılık gösterebilir. Bu, bir dizgeyi bir yerel ayar kullanarak wchar_t'ye dönüştüremeyeceğiniz ve ardından başka bir yerel ayar kullanarak char'a geri dönüştüremeyeceğiniz anlamına gelir. 1

Wchar_t'yi tüm yerel ayarlar arasında ortak bir temsil olarak kullanmak, pratikte wchar_t için birincil kullanım gibi göründüğünden, o değilse ne için iyi olduğunu merak edebilirsiniz.

Wchar_t'nin asıl amacı ve amacı, bir dizenin kod birimlerinden metnin karakterlerine bire bir eşleştirme gerektirecek şekilde tanımlayarak metin işlemeyi basitleştirmektir, böylece kullanılanlarla aynı basit algoritmaların kullanımına izin verir. diğer dillerle çalışmak için ascii dizeleri ile.

Maalesef wchar_t'nin belirtimindeki ifade, bunu başarmak için karakterler ve kod noktaları arasında bire bir eşleştirme olduğunu varsayar. Unicode bu 2 varsayımını bozduğundan, wchar_t'yi basit metin algoritmaları için de güvenle kullanamazsınız.

Bu, taşınabilir yazılımın wchar_t'yi yerel ayarlar arasındaki metnin ortak bir temsili olarak veya basit metin algoritmalarının kullanımını etkinleştirmek için kullanamayacağı anlamına gelir.

Wchar_t bugün ne işe yarar?

Zaten taşınabilir kod için fazla değil. Eğer __STDC_ISO_10646__tanımlanmışsa, wchar_t değerleri doğrudan tüm yerel ayarlarda aynı değerlere sahip Unicode kod noktalarını temsil eder. Bu, daha önce bahsedilen yerel ayarlar arası dönüşümleri yapmayı güvenli hale getirir. Bununla birlikte, yalnızca wchar_t'yi bu şekilde kullanabileceğinize karar vermek için ona güvenemezsiniz çünkü çoğu unix platformu onu tanımlarken, Windows tüm yerel ayarlarda aynı wchar_t yerel ayarını kullansa bile Windows bunu yapmaz.

Windows'un tanımlamamasının __STDC_ISO_10646__nedeni, Windows'un wchar_t kodlaması olarak UTF-16 kullanması ve UTF-16'nın U + FFFF'den daha büyük kod noktalarını temsil etmek için yedek çiftler kullanmasıdır, bu da UTF-16'nın gereksinimlerini karşılamadığı anlamına gelir __STDC_ISO_10646__.

Platforma özel kod için wchar_t daha kullanışlı olabilir. Esasen Windows'ta gereklidir (örneğin, bazı dosyalar wchar_t dosya adları kullanılmadan açılamaz), ancak Windows bildiğim kadarıyla bunun doğru olduğu tek platformdur (bu nedenle wchar_t'yi 'Windows_char_t' olarak düşünebiliriz).

Geriye dönüp bakıldığında wchar_t, metin işlemeyi basitleştirmek için veya yerel ayardan bağımsız metin için depolama olarak açıkça kullanışlı değildir. Taşınabilir kod, onu bu amaçlar için kullanmaya çalışmamalıdır. Taşınabilir olmayan kod, yalnızca bazı API gerektirdiği için yararlı bulabilir.

Alternatifler

Sevdiğim alternatif, UTF-8'e özellikle uygun olmayan platformlarda bile UTF-8 kodlu C dizgilerini kullanmaktır.

Bu şekilde, platformlar arasında ortak bir metin temsili kullanarak taşınabilir kod yazabilir, amaçlanan amaçları için standart veri türlerini kullanabilir, bu türler için dilin desteğini alabilir (örneğin, bazı derleyiciler için çalışmasını sağlamak için bazı hileler gerekli olsa da, dize değişmezleri), bazıları standart kütüphane desteği, hata ayıklayıcı desteği (daha fazla numara gerekli olabilir), vb. Geniş karakterlerle tüm bunları elde etmek genellikle daha zordur veya imkansızdır ve farklı platformlarda farklı parçalar elde edebilirsiniz.

UTF-8'in sağlamadığı bir şey, ASCII ile mümkün olanlar gibi basit metin algoritmalarını kullanma yeteneğidir. Bu UTF-8'de diğer Unicode kodlamalardan daha kötü değildir. Aslında, UTF-8'deki çoklu kodlu birim gösterimleri daha yaygın olduğu için daha iyi olduğu düşünülebilir ve bu nedenle, karakterlerin bu tür değişken genişlikli temsillerini işlemede kodun işlenmesindeki hataların, UTF'ye bağlı kalmaya çalışmanıza göre fark edilmesi ve düzeltilmesi daha olasıdır. NFC veya NFKC ile -32.

Pek çok platform UTF-8'i yerel karakter kodlaması olarak kullanır ve birçok program önemli bir metin işleme gerektirmez ve bu nedenle bu platformlarda uluslararasılaştırılmış bir program yazmak, uluslararasılaştırmayı dikkate almadan kod yazmaktan biraz farklıdır. Daha geniş çapta taşınabilir kod yazmak veya diğer platformlarda yazmak, diğer kodlamaları kullanan API'lerin sınırlarına dönüştürmeler eklemeyi gerektirir.

Bazı yazılımlar tarafından kullanılan başka bir alternatif, UTF-16 verilerini tutan işaretsiz kısa diziler gibi çapraz platform temsilini seçmek ve ardından tüm kitaplık desteğini sağlamak ve dil desteğindeki maliyetlerle yaşamaktır.

C ++ 11, görevli dil / kitaplık özellikleriyle wchar_t, char16_t ve char32_t seçeneklerine alternatif olarak yeni tür geniş karakterler ekler. Bunların UTF-16 ve UTF-32 olması garanti edilmiyor, ancak herhangi bir büyük uygulamanın başka bir şey kullanacağını düşünmüyorum. C ++ 11 ayrıca UTF-8 desteğini de geliştirir, örneğin UTF-8 dize değişmezleri ile VC ++ 'yı UTF-8 kodlu dizeler üretmek için kandırmaya gerek kalmaz (ancak u8öneki kullanmak yerine bunu yapmaya devam edebilirim ) .

Kaçınılması gereken alternatifler

TCHAR: TCHAR, eski kodlamaları char'dan wchar_t'ye taşıyan eski Windows programlarını taşımak içindir ve programınız daha önceki bin yılda yazılmadıysa en iyisi unutulur. Taşınabilir değildir ve kodlaması ve hatta veri türü konusunda doğası gereği belirsizdir, bu da onu TCHAR tabanlı olmayan herhangi bir API ile kullanılamaz hale getirir. Amacı yukarıda gördüğümüz wchar_t'ye geçiş olduğu için iyi bir fikir olmadığından, TCHAR kullanmanın hiçbir değeri yoktur.


1. wchar_t dizelerinde gösterilebilen ancak herhangi bir yerel ayarda desteklenmeyen karakterlerin tek bir wchar_t değeriyle temsil edilmesi gerekmez. Bu, wchar_t'nin belirli karakterler için değişken genişlik kodlaması kullanabileceği anlamına gelir, bu da wchar_t'nin amacının bir başka açık ihlali. Wchar_t ile temsil edilebilen bir karakterin, yerel ayarın bu karakteri 'desteklediğini' söylemek için yeterli olduğu tartışılabilir olsa da, bu durumda değişken genişlikli kodlamalar yasal değildir ve Window'un UTF-16 kullanımı uyumlu değildir.

2. Unicode, birçok karakterin birden çok kod noktasıyla temsil edilmesine izin verir, bu da basit metin algoritmaları için değişken genişlik kodlamalarıyla aynı sorunları yaratır. Bir kişi birleşik bir normalleştirmeyi kesinlikle sürdürse bile, bazı karakterler yine de birden çok kod noktası gerektirir. Bakınız: http://www.unicode.org/standard/where/


3
Ekleme: utf8everywhere.org , Windows'ta UTF-8 kullanılmasını önerir ve Boost.Nowide resmi inceleme için planlanmıştır.
Yakov Galka

2
En iyisi, elbette, Windows'ta C # veya VB.Net kullanmaktır :) Veya eski C / Win32. Ancak C ++ kullanmanız gerekiyorsa, TCHAR gitmenin en iyi yoludur. MSVS2005 ve sonraki sürümlerinde varsayılan "wchar_t" dir. IMHO ...
paulsm4

4
@BrendanMcK: Elbette, Windows'ta Win32 API'yi ve diğer sistemlerdeki diğer API'leri kullanan kod mevcut değil. Sağ? Microsoft'un yaklaşımındaki sorun ("wchar'ı uygulamanızın her yerinde dahili olarak kullanın"), sistemle doğrudan arabirim oluşturmayan ve taşınabilir olabilecek kodu bile etkilemesidir .
Yakov Galka

4
Sorun, Windows'a özgü işlevleri kullanmanız gerektiğidir , çünkü Microsoft'un UTF-8'i bir ANSI kod sayfası olarak desteklememe kararı, Standart C (++) Kitaplığını "bozar". Örneğin fopen, adı ANSI olmayan karakterler içeren bir dosyayı kullanamazsınız .
dan04

11
@ dan04 Evet, Windows'ta standart kitaplığı kullanamazsınız, ancak Win32 W işlevlerini kullanmadan önce standart kitaplığı diğer platformlarda saran ve UTF-8'den wchar_t'ye dönüştüren taşınabilir bir arabirim oluşturabilirsiniz.
bames53

20

Wchar_t ile "yanlış" bir şey yok. Sorun şu ki, NT 3.x günlerinde Microsoft, Unicode'un İyi (öyle) olduğuna ve Unicode'u 16 bit, wchar_t karakterleri olarak uygulamaya karar verdi. Dolayısıyla, 90'ların ortalarından kalma çoğu Microsoft literatürü hemen hemen eşit Unicode == utf16 == wchar_t.

Ne yazık ki, durum hiç de öyle değil. "Geniş karakterler" her koşulda tüm platformlarda 2 bayt olmak zorunda değildir .

Ben: Bu "Unicode" (Bu soruya bağımsız C bağımsız ++) şimdiye kadar gördüğüm en iyi primerlerin biridir derece tavsiye:

Ve "8-bit ASCII" ile "Win32 geniş karakterleri" ve "wchar_t-genel" ile başa çıkmanın en iyi yolunun "Windows'un Farklı olduğunu" kabul etmek ve buna göre kodlamak olduğuna inanıyorum.

BENİM NACİZANE FİKRİME GÖRE...

Not:

Jamesdlin'e tamamen katılıyorum:

Windows'ta gerçekten bir seçeneğiniz yok. Dahili API'leri, değişken uzunluklu UTF-8 ve UTF-16 kodlamalarının standartlaştırılmasından önceki dönemden beri makul olan UCS-2 için tasarlanmıştır. Ama şimdi UTF-16'yı destekledikleri için, her iki dünyanın da en kötüsüyle sonuçlandılar.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.