Apakah TCHAR masih relevan?

87

Saya baru mengenal pemrograman Windows dan setelah membaca buku Petzold saya bertanya-tanya:

apakah masih merupakan praktik yang baik untuk menggunakan TCHARtipe dan _T()fungsi untuk mendeklarasikan string atau jika saya harus menggunakan wchar_tdan L""string dalam kode baru?

Saya hanya akan menargetkan Windows 2000 dan yang lebih baru dan kode saya akan menjadi i18n sejak awal.

Fábio
sumber

Jawaban:

15

Saya masih akan menggunakan sintaks TCHAR jika saya melakukan proyek baru hari ini. Tidak banyak perbedaan praktis antara menggunakannya dan sintaks WCHAR, dan saya lebih suka kode yang eksplisit dalam jenis karakternya. Karena sebagian besar fungsi API dan objek pembantu mengambil / menggunakan tipe TCHAR (misalnya: CString), maka masuk akal untuk menggunakannya. Selain itu, ini memberi Anda fleksibilitas jika Anda memutuskan untuk menggunakan kode dalam aplikasi ASCII di beberapa titik, atau jika Windows pernah berevolusi ke Unicode32, dll.

Jika Anda memutuskan untuk menggunakan rute WCHAR, saya akan menjelaskannya secara eksplisit. Artinya, gunakan CStringW sebagai ganti CString, dan transmisikan makro saat mengonversi ke TCHAR (misalnya: CW2CT).

Itu pendapat saya.

Nick
sumber
Memang, itulah yang akan tetap berfungsi ketika pengkodean karakter pada akhirnya diubah '' lagi ''.
Medinoc
11
Anda lebih suka kode yang eksplisit dalam tipe karakter apa, dan karenanya menggunakan tipe yang terkadang ini dan terkadang itu? Sangat persuasif.
Deduplicator
4
−1 untuk ketidakkonsistenan yang dicatat oleh @Deduplicator, dan untuk saran hasil negatif untuk menggunakan makro yang dapat berupa apa saja (dan umumnya tidak akan diuji untuk lebih dari satu nilai tertentu).
Cheers and hth. - Alf
90

Jawaban singkatnya: TIDAK .

Seperti semua yang sudah ditulis, banyak programmer masih menggunakan TCHAR dan fungsi yang sesuai. Menurut pendapat saya , seluruh konsep adalah ide yang buruk . Pemrosesan string UTF-16 jauh berbeda dari pemrosesan string ASCII / MBCS sederhana. Jika Anda menggunakan algoritme / fungsi yang sama dengan keduanya (inilah yang menjadi dasar ide TCHAR!), Anda mendapatkan kinerja yang sangat buruk pada versi UTF-16 jika Anda melakukan sedikit lebih banyak daripada penggabungan string sederhana (seperti parsing dll.). Alasan utamanya adalah Pengganti .

Dengan satu-satunya pengecualian ketika Anda benar - benar harus mengkompilasi aplikasi Anda untuk sistem yang tidak mendukung Unicode, saya tidak melihat alasan untuk menggunakan bagasi ini dari masa lalu di aplikasi baru.

Sascha
sumber
6
Fakta menarik: UTF-16 tidak selalu ada di platform NT. Poin kode pengganti diperkenalkan dengan Unicode 2.0, pada tahun 1996, yang merupakan tahun yang sama dengan rilis NT 4. Hingga, IIRC, (termasuk) Windows 2000 semua versi NT menggunakan UCS-2, secara efektif merupakan subset dari UTF-16 yang mengasumsikan setiap karakter dapat diwakili dengan satu titik kode (yaitu tidak ada pengganti).
0xC0000022L
3
btw, sementara saya setuju itu TCHARtidak boleh digunakan lagi, saya tidak setuju bahwa ini adalah ide yang buruk. Saya juga berpikir bahwa jika Anda memilih untuk menjadi eksplisit daripada menggunakan TCHARAnda harus eksplisit di mana-mana . Ie tidak menggunakan fungsi dengan TCHAR/ _TCHAR(seperti _tmain) dalam deklarasi mereka. Sederhananya: konsisten. +1, masih.
0xC0000022L
3
Itu adalah ide yang bagus saat diperkenalkan, tetapi seharusnya tidak relevan dalam kode baru.
Adrian McCarthy
4
Anda salah mengartikan, apa TCHARyang awalnya diperkenalkan untuk: Untuk memudahkan pengembangan kode untuk Windows versi berbasis Win 9x dan Windows NT. Pada saat itu, implementasi UTF-16 Windows NT adalah UCS-2, dan algoritma untuk penguraian / manipulasi string identik. Tidak ada pengganti. Dan bahkan dengan pengganti, algoritme untuk DBCS (satu-satunya pengkodean MBCS yang didukung untuk Windows) dan UTF-16 adalah sama: Dalam salah satu pengkodean, titik kode terdiri dari satu atau dua unit kode.
IInspectable
Misalkan saya ingin menggunakan FormatMessage () untuk mengonversi nilai dari WSAGetLastError () menjadi sesuatu yang dapat dicetak. Dokumentasi untuk WSAGetLastError () mengatakan bahwa dibutuhkan LPTSTR sebagai penunjuk ke buffer. Saya benar-benar tidak punya banyak pilihan selain menggunakan TCHAR, bukan?
Edward Falk
81

Saya harus setuju dengan Sascha. Premis yang mendasari TCHAR/_T() / etc. adalah Anda dapat menulis aplikasi berbasis "ANSI" dan kemudian secara ajaib memberinya dukungan Unicode dengan mendefinisikan makro. Tetapi ini didasarkan pada beberapa asumsi buruk:

Bahwa Anda secara aktif membangun versi MBCS dan Unicode dari perangkat lunak Anda

Jika tidak, Anda akan tergelincir dan menggunakan biasachar* string di banyak tempat.

Bahwa Anda tidak menggunakan pelolosan garis miring terbalik non-ASCII dalam literal _T ("...")

Kecuali pengkodean "ANSI" Anda kebetulan ISO-8859-1, hasil char*dan wchar_t*literal tidak akan mewakili karakter yang sama.

String UTF-16 tersebut digunakan seperti string "ANSI"

Mereka tidak. Unicode memperkenalkan beberapa konsep yang tidak ada di sebagian besar pengkodean karakter lama. Pengganti. Menggabungkan karakter. Normalisasi. Aturan kapitalisasi bersyarat dan peka bahasa.

Dan mungkin yang paling penting, fakta bahwa UTF-16 jarang disimpan di disk atau dikirim melalui Internet: UTF-8 cenderung lebih disukai untuk representasi eksternal.

Bahwa aplikasi Anda tidak menggunakan Internet

(Sekarang, ini mungkin asumsi yang valid untuk Anda perangkat lunak , tetapi ...)

Web berjalan pada UTF-8 dan sejumlah besar pengkodean yang lebih jarang . The TCHARKonsep hanya mengakui dua: "ANSI" (yang tidak bisa menjadi UTF-8 ) dan "Unicode" (UTF-16). Ini mungkin berguna untuk membuat panggilan Windows API Anda sadar-Unicode, tetapi itu sangat tidak berguna untuk membuat aplikasi web dan email Anda sadar-Unicode.

Bahwa Anda tidak menggunakan perpustakaan non-Microsoft

Tidak ada orang lain yang menggunakan TCHAR. Poco menggunakan std::stringdan UTF-8. SQLite memiliki API versi UTF-8 dan UTF-16, tetapi tidak TCHAR. TCHARbahkan tidak ada di pustaka standar, jadi tidak, std::tcoutkecuali Anda ingin mendefinisikannya sendiri.

Yang saya rekomendasikan, bukan TCHAR

Lupakan bahwa pengkodean "ANSI" ada, kecuali saat Anda perlu membaca file yang bukan UTF-8 yang valid. Lupakan TCHARjuga. Selalu panggil fungsi Windows API versi "W". #define _UNICODEhanya untuk memastikan Anda tidak memanggil fungsi "A" secara tidak sengaja.

Selalu gunakan encoding UTF untuk string: UTF-8 untuk charstring dan UTF-16 (di Windows) atau UTF-32 (pada sistem mirip Unix) untuk wchar_tstring. typedef UTF16dan UTF32tipe karakter untuk menghindari perbedaan platform.

dan04
sumber
6
Panggilan 2012: masih ada aplikasi yang harus dipertahankan #define _UNICODEbahkan sampai sekarang. Akhir transmisi :)
0xC0000022L
12
@ 0xC0000022L pertanyaannya adalah tentang kode baru . Ketika Anda mempertahankan kode lama, Anda jelas harus bekerja dengan lingkungan yang kode ditulis untuk. Jika Anda memelihara aplikasi COBOL, maka tidak masalah apakah COBOL adalah bahasa yang bagus atau tidak, Anda terjebak dengannya. Dan jika Anda mengelola aplikasi yang bergantung pada TCHAR, tidak masalah apakah itu keputusan yang baik atau tidak, Anda tidak dapat melakukannya.
jalf
2
Memang, TCHAR tidak berguna kecuali di COBOL)
Pavel Radzivilovsky
1
_UNICODEmengontrol bagaimana pemetaan teks generik diselesaikan di CRT. Jika Anda tidak ingin memanggil versi ANSI dari Windows API, Anda perlu menentukan UNICODE.
IInspectable
18

Jika Anda bertanya-tanya apakah itu masih dalam praktik, maka ya - itu masih digunakan cukup banyak. Tidak ada yang akan melihat kode Anda lucu jika menggunakan TCHAR dan _T (""). Proyek yang saya kerjakan sekarang sedang mengubah dari ANSI ke unicode - dan kami akan menggunakan rute portabel (TCHAR).

Namun...

Pilihan saya adalah melupakan semua makro portabel ANSI / UNICODE (TCHAR, _T (""), dan semua panggilan _tXXXXXX, dll ...) dan menganggap unicode di mana-mana. Saya benar-benar tidak melihat gunanya menjadi portabel jika Anda tidak akan membutuhkan versi ANSI. Saya akan menggunakan semua fungsi dan tipe karakter lebar secara langsung. Preprend semua string literal dengan L.

tapir
sumber
3
Anda mungkin menulis beberapa kode yang ingin Anda gunakan di tempat lain di mana Anda memang membutuhkan versi ANSI, atau (seperti yang dikatakan Nick) Windows mungkin pindah ke DCHAR atau apa pun, jadi saya masih berpikir itu ide yang sangat baik untuk menggunakan TCHAR daripada WCHAR.
arkeolog
Saya ragu Windows akan beralih ke UTF-32.
dan04
7
-1 untuk rekomendasi UTF-16. Tidak hanya ini membuat kode non-portabel (windows-centric), yang tidak dapat diterima untuk perpustakaan - meskipun dapat digunakan untuk kasus yang paling sederhana seperti kode UI - itu tidak efisien bahkan di Windows itu sendiri. utf8everywhere.org
Pavel Radzivilovsky
11

Artikel Pengantar Pemrograman Windows di MSDN mengatakan

Aplikasi baru harus selalu memanggil versi Unicode (dari API).

The TEXT dan TCHAR macro kurang berguna hari ini, karena semua aplikasi harus menggunakan Unicode.

Saya akan tetap berpegang pada wchar_tdan L"".

Steven
sumber
4
Steven, Anda mengutip teks yang ditulis oleh seseorang yang tidak mengerti arti kata 'Unicode'. Ini adalah salah satu dokumen yang tidak menguntungkan dari saat kebingungan UCS-2.
Pavel Radzivilovsky
2
@PavelRadzivilovsky: Dokumen ditulis untuk sistem, di mana Unicode dan UTF-16LE biasanya digunakan secara bergantian. Meskipun secara teknis tidak akurat, ini tidak ambigu. Ini juga secara eksplisit ditunjukkan dalam pengenalan teks yang sama: "Windows mewakili karakter Unicode menggunakan pengkodean UTF-16 [...]" .
IInspectable
11

Saya ingin menyarankan pendekatan yang berbeda (tidak satu pun dari keduanya).

Untuk meringkas, gunakan char * dan std :: string, dengan asumsi encoding UTF-8, dan lakukan konversi ke UTF-16 hanya saat menggabungkan fungsi API.

Informasi lebih lanjut dan justifikasi untuk pendekatan ini dalam program Windows dapat ditemukan di http://www.utf8everywhere.org .

Pavel Radzivilovsky
sumber
@PavelRadzivilovsky, saat mengimplementasikan saran Anda dalam aplikasi VC ++, apakah kita akan menyetel karakter VC ++ ke 'None' atau 'Multibyte (MBCS)'? Alasan saya bertanya adalah karena saya baru saja menginstal Boost :: Locale dan set karakter default adalah MBCS. FWIW, aplikasi ASCII murni saya disetel ke 'Tidak Ada' dan sekarang saya telah menyetelnya ke 'MBCS' (karena saya akan menggunakan Boost :: Locale di dalamnya) dan berfungsi dengan baik. Mohon saran.
Caroline Beltran
Seperti yang disarankan utf8everywhere, saya akan menyetelnya ke 'Gunakan kumpulan karakter Unicode'. Iklan ini keamanan ekstra, tetapi tidak diperlukan. Penulis Boost :: locale adalah orang yang sangat cerdas, saya yakin dia melakukan hal yang benar.
Pavel Radzivilovsky
3
Itu UTF-8 Mana mantra tidak akan menjadi solusi yang tepat, hanya karena diulang lebih sering. UTF-8 tidak diragukan lagi merupakan pengkodean yang menarik untuk serialisasi (misalnya file, atau soket jaringan), tetapi pada Windows sering kali lebih tepat, untuk menyimpan data karakter menggunakan pengkodean UTF-16 asli secara internal, dan mengonversi pada batas aplikasi. Salah satu alasannya adalah, UTF-16 adalah satu-satunya pengkodean, yang dapat langsung dikonversi ke pengkodean lain yang didukung. Ini tidak terjadi pada UTF-8.
IInspectable
"..UTF-16 adalah satu-satunya pengkodean, yang dapat segera dikonversi ke pengkodean lain yang didukung." maksud kamu apa? Apa masalah untuk mengonversi pengkodean UTF-8 ke yang lain?
Pavel Radzivilovsky
1
Saya tidak mengerti. Untuk hal lain - seperti apa? Misalnya UCS-4? Kenapa tidak? Sepertinya sangat mudah, semua algoritma numerik ..
Pavel Radzivilovsky
7

TCHARSaya WCHARmungkin cukup untuk beberapa proyek lama. Tetapi untuk aplikasi baru, saya akan mengatakan TIDAK .

Semua ini TCHAR/ WCHARbarang ada karena alasan sejarah. TCHARmenyediakan cara yang tampaknya rapi (menyamar) untuk beralih antara pengkodean teks ANSI (MBCS) dan pengkodean teks Unicode (UTF-16). Dahulu, orang tidak memiliki pemahaman tentang jumlah karakter dari semua bahasa di dunia. Mereka mengasumsikan 2 byte cukup untuk mewakili semua karakter dan dengan demikian memiliki skema pengkodean karakter dengan panjang tetap yang digunakan WCHAR. Namun, ini tidak lagi benar setelah rilis Unicode 2.0 pada tahun 1996 .

Artinya: Apa pun yang Anda gunakan di CHAR/ WCHAR/ TCHAR, bagian pemrosesan teks dalam program Anda harus dapat menangani karakter dengan panjang variabel untuk internasionalisasi.

Jadi, Anda sebenarnya perlu melakukan lebih dari sekadar memilih satu dari CHAR/ WCHAR/ TCHARuntuk pemrograman di Windows:

  1. Jika aplikasi Anda kecil dan tidak melibatkan pemrosesan teks (yaitu, hanya meneruskan string teks sebagai argumen), maka tetap gunakan WCHAR . Karena cara ini lebih mudah untuk bekerja dengan WinAPI dengan dukungan Unicode.
  2. Jika tidak, saya akan menyarankan menggunakan UTF-8 sebagai pengkodean internal dan menyimpan teks dalam string char atau std :: string. Dan sembunyikan mereka ke UTF-16 saat memanggil WinAPI. UTF-8 sekarang menjadi pengkodean yang dominan dan ada banyak pustaka dan alat praktis untuk memproses string UTF-8.

Lihat situs web yang luar biasa ini untuk bacaan yang lebih mendalam: http://utf8everywhere.org/

LeOpArD
sumber
2
"UTF-8 sekarang menjadi pengkodean yang dominan" - Ini menjadi salah, dengan mengabaikan bagian kedua dari kutipan ( "untuk World Wide Web" ). Untuk aplikasi desktop, pengkodean karakter asli yang paling banyak digunakan kemungkinan besar masih UTF-16. Windows menggunakannya, Mac OS X juga menggunakannya, begitu juga jenis string .NET dan Java. Itu menyumbang sejumlah besar kode di luar sana. Jangan salah paham, tidak ada yang salah dengan UTF-8 untuk serialisasi. Tetapi lebih sering daripada tidak (terutama di Windows), Anda akan menemukan, bahwa menggunakan UTF-16 secara internal lebih tepat.
IInspectable
4

Ya, tentu saja; setidaknya untuk makro _T. Saya tidak begitu yakin tentang hal-hal yang berkarakter luas.

Alasannya adalah untuk lebih mendukung WinCE atau platform Windows non-standar lainnya. Jika Anda 100% yakin bahwa kode Anda akan tetap di NT, maka Anda mungkin bisa menggunakan deklarasi C-string biasa. Namun, yang terbaik adalah cenderung ke pendekatan yang lebih fleksibel, karena jauh lebih mudah untuk #menentukan makro itu di platform non-windows dibandingkan dengan menelusuri ribuan baris kode dan menambahkannya di mana-mana jika Anda perlu mem-port beberapa pustaka ke windows mobile.

Nik Reiman
sumber
1
WinCE menggunakan string wchar_t 16-bit seperti Win32. Kami memiliki basis kode besar yang berjalan di WinCE dan Win32 dan kami tidak pernah menggunakan TCHAR.
mhenry1384
2

IMHO, jika ada TCHAR dalam kode Anda, Anda bekerja di tingkat abstraksi yang salah.

Gunakan jenis string apa pun yang paling nyaman bagi Anda saat berurusan dengan pemrosesan teks - semoga ini akan menjadi sesuatu yang mendukung unicode, tetapi itu terserah Anda. Lakukan konversi pada batasan OS API seperlunya.

Saat berurusan dengan jalur file, siapkan jenis kustom Anda sendiri daripada menggunakan string. Ini akan memungkinkan Anda pemisah jalur OS-independen, akan memberi Anda antarmuka yang lebih mudah untuk kode daripada penggabungan dan pemisahan string manual, dan akan jauh lebih mudah untuk beradaptasi dengan OS yang berbeda (ansi, ucs-2, utf-8, apa pun) .

snemarch
sumber
Unicode memiliki setidaknya tiga encoding saat ini (UTF-8, UTF-16, UTF-32) dan satu encoding yang tidak digunakan lagi (UCS-2, subset dari apa yang sekarang disebut UTF-16). Yang mana yang Anda maksud? Saya suka saran lainnya meskipun +1
0xC0000022L
2

Satu-satunya alasan saya melihat untuk menggunakan apa pun selain WCHAR eksplisit adalah portabilitas dan efisiensi.

Jika Anda ingin membuat eksekusi akhir Anda sekecil mungkin, gunakan char.

Jika Anda tidak peduli tentang penggunaan RAM dan ingin internasionalisasi menjadi semudah terjemahan sederhana, gunakan WCHAR.

Jika Anda ingin membuat kode Anda fleksibel, gunakan TCHAR.

Jika Anda hanya berencana menggunakan karakter Latin, Anda sebaiknya menggunakan string ASCII / MBCS sehingga pengguna Anda tidak membutuhkan banyak RAM.

Untuk orang yang "i18n dari awal", hemat ruang kode sumber dan cukup gunakan semua fungsi Unicode.

Trololol
sumber
-1

Hanya menambahkan ke pertanyaan lama:

TIDAK

Mulailah proyek CLR C ++ baru di VS2010. Microsoft sendiri menggunakan L"Hello World", 'kata nuff.

kizzx2
sumber
13
CLR adalah lingkungan yang sangat berbeda dari kode yang tidak dikelola. Itu bukan argumen.
Cody Gray
3
Bahkan Microsoft membuat kesalahan.
Pavel Radzivilovsky
6
-1 Pertanyaannya diberi tag Cdan C++. Jawaban selalu dapat dihapus oleh penulisnya masing-masing. Ini akan menjadi saat yang tepat untuk menggunakan ketentuan itu.
IInspectable