TCHAR hala geçerli mi?


87

Windows programlama konusunda yeniyim ve Petzold kitabını okuduktan sonra merak ediyorum:

dizeleri bildirmek için TCHARtürü ve _T()işlevi kullanmak hala iyi bir uygulama mı yoksa yeni kodda yalnızca wchar_tve L""dizelerini kullanmalı mıyım?

Yalnızca Windows 2000 ve üzerini hedefleyeceğim ve kodum başlangıçtan itibaren i18n olacak .

Yanıtlar:


15

Bugün yeni bir proje yapıyor olsaydım yine de TCHAR sözdizimini kullanırdım. Kullanmakla WCHAR sözdizimi arasında pek pratik bir fark yok ve ben karakter türünün ne olduğu konusunda açık olan kodu tercih ediyorum. Çoğu API işlevi ve yardımcı nesne TCHAR türlerini aldığı / kullandığı için (örneğin: CString), onu kullanmak mantıklıdır. Ayrıca, kodu bir noktada ASCII uygulamasında kullanmaya karar verirseniz veya Windows Unicode32'ye dönüşürse, size esneklik sağlar.

WCHAR rotasına gitmeye karar verirseniz, bu konuda açık olurum. Yani, CString yerine CStringW kullanın ve TCHAR'a dönüştürürken makroları yayınlayın (örneğin: CW2CT).

Her neyse, bu benim fikrim.


Nitekim, karakter kodlaması sonunda "tekrar" değiştirildiğinde hala işe yarayacak olan şey budur.
Medinoc

11
Karakter türünde açık olan kodu tercih ediyorsunuz ve bu nedenle bazen bu ve bazen bu olan bir tür mü kullanıyorsunuz? Çok ikna edici.
Deduplicator

4
-1 @Deduplicator ile, ve ne olursa olsun (ve genellikle birden fazla belirli bir değeri test edilmez) olabilir bir makro kullanmak üzere negatif ödeme tavsiye belirtildiği tutarsızlığın.
Şerefe ve hth. - Alf

90

Kısa cevap: HAYIR .

Diğerlerinin zaten yazdığı gibi, birçok programcı hala TCHAR'ları ve bunlara karşılık gelen işlevleri kullanıyor. Benim naçizane fikrime göre tüm konsept kötü bir fikirdi . UTF-16 dizge işleme, basit ASCII / MBCS dizgi işlemeden çok farklıdır. Her ikisiyle de aynı algoritmaları / işlevleri kullanırsanız (TCHAR fikrinin temeli budur!), Basit dizgi birleştirmeden biraz daha fazlasını yapıyorsanız UTF-16 sürümünde çok kötü performans elde edersiniz (örneğin ayrıştırma vb.). Ana neden, Suretler .

Tek istisna olan ne zaman gerçekten Unicode Yeni bir uygulamada geçmişten bu bagajı kullanmak için hiçbir neden görmüyorum desteklemeyen bir sistem için başvurunuzu derlemeliyiz.


6
Eğlenceli gerçek: UTF-16, NT platformunda her zaman orada değildi. Vekil kod noktaları, 1996 yılında, NT 4'ün piyasaya sürüldüğü yıl olan Unicode 2.0 ile tanıtıldı. IIRC'ye kadar (Windows 2000 dahil) tüm NT sürümleri, her karakterin bir kod noktasıyla temsil edilebileceğini varsayan (yani yerine geçmeyen) UTF-16'nın etkili bir alt kümesi olan UCS-2'yi kullanıyordu.
0xC0000022L

3
btw, TCHARartık kullanılmaması gerektiğini kabul ederken , bunun kötü bir fikir olduğuna katılmıyorum. Ben de düşünüyorum eğer seçtiğiniz kullanmak yerine açık olmak TCHARmüstehcen olmalı her yerde . Bildirimlerinde TCHAR/ _TCHAR(gibi _tmain) işlevlerini de kullanmam . Basitçe söylemek gerekirse: tutarlı olun. Hala +1.
0xC0000022L

3
Bu iyi bir fikir olduğunu o tanıtıldığında geri, ama yeni kodda alakasız olmalıdır.
Adrian McCarthy

4
TCHARBaşlangıçta ne için tanıtıldığını yanlış beyan ediyorsunuz : Windows'un Win 9x ve Windows NT tabanlı sürümleri için kod geliştirmeyi kolaylaştırmak için. O sırada, Windows NT'nin UTF-16 uygulaması UCS-2 idi ve dize ayrıştırma / işleme algoritmaları aynıydı. Suret yoktu. Yinelemelerde bile, DBCS (Windows için desteklenen tek MBCS kodlaması) ve UTF-16 için algoritmalar aynıdır: Her iki kodlamada da bir kod noktası bir veya iki kod biriminden oluşur.
IInspectable

WSAGetLastError () 'dan bir değeri yazdırılabilir bir şeye dönüştürmek için FormatMessage () kullanmak istediğimi varsayalım. WSAGetLastError () dokümantasyonu, arabelleğe işaretçi olarak LPTSTR'yi aldığını söylüyor. TCHAR kullanmaktan başka seçeneğim yok, değil mi?
Edward Falk

81

Sascha'ya katılıyorum. TCHAR/ _T()/ Vb .'nin temel dayanağı, "ANSI" tabanlı bir uygulama yazabilmeniz ve ardından bir makro tanımlayarak sihirli bir şekilde ona Unicode desteği verebilmenizdir. Ancak bu, birkaç kötü varsayıma dayanmaktadır:

Yazılımınızın hem MBCS hem de Unicode sürümlerini aktif olarak oluşturduğunuz

Aksi takdirde, olacak kadar kayma ve sıradan kullanmak char*birçok yerde dizeleri.

_T ("...") değişmez değerlerinde ASCII olmayan ters eğik çizgi kaçışları kullanmadığınız

"ANSI" kodlamanız ISO-8859-1 olmadıkça, sonuç char*ve wchar_t*değişmez değerler aynı karakterleri temsil etmeyecektir.

UTF-16 dizelerinin tıpkı "ANSI" dizeleri gibi kullanıldığı

Onlar değil. Unicode, çoğu eski karakter kodlamasında bulunmayan birkaç kavram sunar. Suretler. Karakterleri birleştirmek. Normalleştirme. Koşullu ve dile duyarlı büyük / küçük harf kuralları.

Ve belki de en önemlisi, UTF-16'nın nadiren diske kaydedilmesi veya İnternet üzerinden gönderilmesi gerçeği: UTF-8 harici gösterim için tercih edilme eğilimindedir.

Uygulamanızın İnternet'i kullanmadığını

(Şimdi, bunun için geçerli bir varsayım olabilir senin ... yazılım, ama)

Web, UTF-8 ve çok sayıda nadir kodlamayla çalışır . TCHARKavram sadece iki tanır: ( "ANSI" olamaz UTF-8 olmak ) ve "Unicode" (UTF-16). Windows API çağrılarınızın Unicode duyarlı olmasını sağlamak için yararlı olabilir, ancak web ve e-posta uygulamalarınızı Unicode duyarlı hale getirmek için kesinlikle yararsızdır.

Microsoft'a ait olmayan kitaplıklar kullanmadığınız

Başka kimse kullanmıyor TCHAR. Poco kullanır std::stringve UTF-8. SQLite , API'sinin UTF-8 ve UTF-16 sürümlerine sahiptir, ancak yoktur TCHAR. TCHARstandart kitaplıkta bile değildir, bu yüzden std::tcoutkendiniz tanımlamak istemediğiniz sürece hayır .

TCHAR yerine ne öneririm

Geçerli UTF-8 olmayan bir dosyayı okumanız gerektiği durumlar dışında "ANSI" kodlamalarının var olduğunu unutun. Siz TCHARde unutun . Her zaman Windows API işlevlerinin "W" sürümünü çağırın. #define _UNICODEsadece yanlışlıkla "A" işlevini çağırmadığınızdan emin olmak için.

Dizeler için her zaman UTF kodlamalarını kullanın: dizeler için UTF-8 ve chardizeler için UTF-16 (Windows'ta) veya UTF-32 (Unix benzeri sistemlerde) wchar_t. typedef UTF16ve UTF32platform farklılıklarından kaçınmak için karakter türleri.


6
2012 çağrısı: #define _UNICODEşimdi bile sürdürülmesi gereken uygulamalar var . İletimin sonu :)
0xC0000022L

12
@ 0xC0000022L soru yeni kod hakkındaydı. Eğer eski kod korumak zaman, belli ki çevre ile işe sahip olduğunu kod için yazılmıştır. Bir COBOL uygulamasına devam ediyorsanız, COBOL'un iyi bir dil olup olmadığı önemli değildir, buna bağlı kalırsınız. Ve TCHAR'a dayanan bir uygulamayı sürdürüyorsanız, bunun iyi bir karar olup olmadığı önemli değildir, buna bağlı kalırsınız.
jalf

2
Gerçekten de, TCHAR, COBOL'de olmadığı sürece yararlı değildir)
Pavel Radzivilovsky

1
_UNICODECRT'de genel metin eşlemelerinin nasıl çözümlendiğini kontrol eder. Bir Windows API'nin ANSI sürümünü çağırmak istemiyorsanız, tanımlamanız gerekir UNICODE.
IInspectable

18

Hala pratikte olup olmadığını merak ediyorsanız, o zaman evet - hala oldukça kullanılıyor. TCHAR ve _T ("") kullanıyorsa kimse kodunuza komik bakmayacaktır. Şu anda üzerinde çalıştığım proje ANSI'den unicode'a dönüştürüyor - ve taşınabilir (TCHAR) rotaya gidiyoruz.

Ancak...

Benim oyum, tüm ANSI / UNICODE taşınabilir makrolarını (TCHAR, _T ("") ve tüm _tXXXXXX çağrılarını, vb.) Unutmak ve her yerde unicode varsaymak olacaktır. Bir ANSI sürümüne asla ihtiyacınız olmayacaksa, taşınabilir olmanın anlamını gerçekten görmüyorum. Tüm geniş karakter işlevlerini ve türlerini doğrudan kullanırdım. Tüm dize değişmezlerini bir L ile ekleyin.


3
ANSI sürümüne ihtiyaç duyduğunuz başka bir yerde kullanmak isteyeceğiniz bir kod yazabilirsiniz veya (Nick'in dediği gibi) Windows DCHAR'a veya her neyse, bu yüzden hala bunun yerine TCHAR ile gitmenin çok iyi bir fikir olduğunu düşünüyorum. WCHAR.
arke

Windows'un UTF-32'ye geçeceğinden şüpheliyim.
dan04

7
UTF-16 önerisi için -1. Yalnızca bu, kütüphaneler için kabul edilemez olan taşınabilir olmayan (Windows merkezli) kod oluşturmakla kalmaz - UI kodu gibi en basit durumlarda kullanılsa bile - Windows'un kendisinde bile verimli değildir. utf8everywhere.org
Pavel Radzivilovsky

11

Giriş Windows Programlama makale MSDN diyor

Yeni uygulamalar her zaman Unicode sürümlerini (API'nin) çağırmalıdır.

METİN ve TCHAR tüm uygulamalar Unicode kullanmalıdır çünkü makrolar bugün daha az yararlıdır.

Ben sopa wchar_tve L"".


4
Steven, 'Unicode' kelimesinin anlamını anlamayan biri tarafından yazılmış bir metinden alıntı yapıyorsun. UCS-2'nin kafa karışıklığı döneminden kalma talihsiz belgelerden biridir.
Pavel Radzivilovsky

2
@PavelRadzivilovsky: Belge, Unicode ve UTF-16LE'nin genellikle birbirinin yerine kullanıldığı bir sistem için yazılmıştır . Teknik olarak doğru olmasa da yine de belirsizdir. Bu aynı metnin girişinde de açıkça belirtilmiştir: "Windows, UTF-16 kodlamasını [...] kullanan Unicode karakterlerini temsil eder" .
2016

11

Farklı bir yaklaşım önermek isterim (ikisi de değil).

Özetlemek için, UTF-8 kodlamasını varsayarak char * ve std :: string kullanın ve UTF-16'ya dönüşümleri yalnızca API işlevlerini sararken yapın.

Windows programlarında bu yaklaşım için daha fazla bilgi ve gerekçe http://www.utf8everywhere.org adresinde bulunabilir .


@PavelRadzivilovsky, önerinizi bir VC ++ uygulamasında uygularken, VC ++ karakterini 'Yok' veya 'Multibyte (MBCS)' olarak ayarlar mıydık? Sormamın nedeni Boost :: Locale'i yeni kurmuş olmam ve varsayılan karakter setinin MBCS olması. FWIW, saf ASCII uygulamam 'Yok' olarak ayarlandı ve şimdi onu 'MBCS' olarak ayarladım (içinde Boost :: Locale kullanacağımdan beri) ve gayet iyi çalışıyor. Tavsiye lütfen.
Caroline Beltran

Utf8everywhere'in önerdiği gibi, onu 'Unicode karakter setini kullan' olarak ayarlardım. Bu ekstra güvenlik sağlar, ancak gerekli değildir. Boost :: locale'nin yazarı çok akıllı bir adam, eminim doğru olanı yaptı.
Pavel Radzivilovsky

3
UTF-8 Heryerde mantra daha sık tekrarlanır sırf doğru çözüm olmayacaktır. UTF-8 şüphesiz serileştirme için çekici bir kodlamadır (örn. Dosyalar veya ağ soketleri), ancak Windows'ta karakter verilerini dahili olarak yerel UTF-16 kodlamasını kullanarak depolamak ve uygulama sınırında dönüştürmek genellikle daha uygundur. Bunun bir nedeni, UTF-16'nın, desteklenen herhangi bir başka kodlamaya anında dönüştürülebilen tek kodlama olmasıdır. UTF-8'de durum böyle değildir.
2016

"..UTF-16, desteklenen herhangi bir başka kodlamaya anında dönüştürülebilen tek kodlamadır." ne demek istiyorsun? UTF-8 kodlamasını başka bir şeye dönüştürmenin sorunu nedir?
Pavel Radzivilovsky

1
Anlayamıyorum. Başka bir şeye - ne gibi? Örneğin UCS-4? Neden olmasın? Çok kolay görünüyor, tüm sayısal algoritma ..
Pavel Radzivilovsky

7

TCHAR/ WCHARBazı eski projeler için yeterli olabilir. Ancak yeni uygulamalar için HAYIR derdim .

Bütün bunlar TCHAR/ WCHARşeyler tarihsel nedenlerden dolayı var. TCHARANSI metin kodlaması (MBCS) ve Unicode metin kodlaması (UTF-16) arasında geçiş yapmak için görünüşte düzgün bir yol (gizleme) sağlar. Geçmişte insanlar dünyadaki tüm dillerin karakter sayısını anlamıyorlardı. Tüm karakterleri temsil etmek için 2 baytın yeterli olduğunu ve dolayısıyla sabit uzunlukta bir karakter kodlama şemasına sahip olduklarını varsaydılar WCHAR. Ancak, Unicode 2.0'ın 1996'da piyasaya sürülmesinden sonra bu artık geçerli değildir .

Yani: CHAR/ WCHAR/ içinde hangisini kullanırsanız kullanın TCHAR, programınızdaki metin işleme kısmı uluslararasılaştırma için değişken uzunlukta karakterleri işleyebilmelidir .

Yani aslında Windows'ta programlama için CHAR/ WCHAR/ içinden birini seçmekten daha fazlasını yapmanız gerekir TCHAR:

  1. Uygulamanız küçükse ve metin işlemeyi içermiyorsa (yani sadece metin dizesini bağımsız değişken olarak geçirme), o zaman devam edin WCHAR. Unicode destekli WinAPI ile bu şekilde çalışmak daha kolay olduğu için.
  2. Aksi takdirde, UTF-8'i dahili kodlama olarak kullanmanızı ve metinleri char dizeleri veya std :: string olarak saklamanızı öneririm. WinAPI'yi çağırırken bunları UTF-16'ya dönüştürün. UTF-8 artık baskın kodlamadır ve UTF-8 dizelerini işlemek için birçok kullanışlı kitaplık ve araç vardır.

Daha derinlemesine okumak için bu harika web sitesine göz atın: http://utf8everywhere.org/


2
"UTF-8 artık baskın kodlamadır" - Bu, alıntının ikinci bölümünü ( "World Wide Web için" ) dışarıda bırakarak yanlış oldu . Masaüstü uygulamaları için en çok kullanılan yerel karakter kodlaması muhtemelen hala UTF-16'dır. Windows bunu kullanıyor, Mac OS X de kullanıyor ve .NET ve Java'nın dize türleri de kullanıyor. Bu , orada büyük miktarda kod anlamına gelir. Beni yanlış anlamayın, UTF-8 serileştirmede yanlış bir şey yok. Ancak çoğu zaman (özellikle Windows'ta), UTF-16'yı dahili olarak kullanmanın daha uygun olduğunu göreceksiniz.
IInspectable

4

Evet kesinlikle; en azından _T makrosu için. Yine de geniş karakterli şeylerden pek emin değilim.

Bunun nedeni, WinCE'yi veya diğer standart olmayan Windows platformlarını daha iyi desteklemektir. Kodunuzun NT'de kalacağından% 100 eminseniz, muhtemelen normal C-string bildirimlerini kullanabilirsiniz. Bununla birlikte, daha esnek bir yaklaşıma yönelmek en iyisidir, çünkü bu makroyu Windows olmayan bir platformda tanımlamak, binlerce satır koddan geçmek ve bazı kitaplıkları taşımanız gerektiğinde onu her yere eklemekle karşılaştırıldığında çok daha kolaydır. Windows mobile'a.


1
WinCE, Win32 gibi 16 bitlik wchar_t dizeleri kullanır. WinCE ve Win32 üzerinde çalışan geniş bir kod tabanımız var ve asla TCHAR kullanmıyoruz.
mhenry1384

2

IMHO, kodunuzda TCHAR'lar varsa, yanlış soyutlama düzeyinde çalışıyorsunuz demektir.

Kullanım neyse bu umutla şey destekleyen unicode olacak, ama bu size kalmış - metin işleme ile uğraşırken dize türü sizin için en uygundur. Gerektiği gibi, OS API sınırlarında dönüştürme yapın.

Dosya yollarıyla uğraşırken, dizeleri kullanmak yerine kendi özel türünüzü oluşturun. Bu, işletim sisteminden bağımsız yol ayırıcılara izin verir, size manuel dize birleştirme ve bölmeye göre kodlama için daha kolay bir arayüz sağlar ve farklı işletim sistemlerine (ansi, ucs-2, utf-8, ne olursa olsun) uyarlamak çok daha kolay olacaktır. .


Unicode'da en az üç güncel kodlama (UTF-8, UTF-16, UTF-32) ve kullanımdan kaldırılmış bir kodlama (UCS-2, şimdi UTF-16 olanın bir alt kümesi) vardır. Hangisini kastediyorsun? Yine de önerilerin geri kalanını beğendim +1
0xC0000022L

2

Açık WCHAR dışında herhangi bir şey kullanmamın tek nedeni taşınabilirlik ve verimliliktir.

Son çalıştırılabilir dosyanızı olabildiğince küçük yapmak istiyorsanız, char kullanın.

RAM kullanımını önemsemiyorsanız ve uluslararasılaştırmanın basit çeviri kadar kolay olmasını istiyorsanız, WCHAR'ı kullanın.

Kodunuzu esnek hale getirmek istiyorsanız, TCHAR kullanın.

Yalnızca Latin karakterleri kullanmayı planlıyorsanız, ASCII / MBCS dizelerini de kullanabilirsiniz, böylece kullanıcınız çok fazla RAM'e ihtiyaç duymaz.

"Başlangıçtan itibaren i18n" olan kişiler için, kaynak kodu alanından tasarruf edin ve tüm Unicode işlevlerini kullanın.


-1

Sadece eski bir soruya ekliyoruz:

HAYIR

VS2010'da yeni bir CLR C ++ projesi başlatın. Microsoft'un kendisi kullanıyor L"Hello World", 'dedi.


13
CLR, yönetilmeyen koddan çok farklı bir ortamdır. Bu bir tartışma değil .
Cody Grey

3
Microsoft bile hata yapıyor.
Pavel Radzivilovsky

6
-1 Soru etiketlendi Cve C++. Cevaplar her zaman kendi yazarları tarafından silinebilir. Bu hükmü kullanmak için iyi bir zaman olacaktır.
2013

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.