Saya telah melihat banyak orang di komunitas C ++ (terutama ## c ++ di freenode) membenci penggunaan wstrings
dan wchar_t
, dan penggunaannya di api windows. Apa sebenarnya yang "salah" dengan wchar_t
dan wstring
, dan jika saya ingin mendukung internasionalisasi, apa sajakah alternatif untuk karakter yang luas?
87
Jawaban:
Apa itu wchar_t?
wchar_t didefinisikan sedemikian rupa sehingga pengkodean char lokal apa pun dapat dikonversi ke representasi wchar_t di mana setiap wchar_t mewakili tepat satu titik kode:
Ini tidak mengharuskan wchar_t cukup besar untuk mewakili karakter apa pun dari semua lokal secara bersamaan. Artinya, encoding yang digunakan untuk wchar_t mungkin berbeda di antara bahasa lokal. Yang berarti Anda tidak bisa serta merta mengonversi string menjadi wchar_t menggunakan satu lokal dan kemudian mengonversi kembali ke char menggunakan lokal lain. 1
Karena menggunakan wchar_t sebagai representasi umum antara semua lokal tampaknya menjadi penggunaan utama untuk wchar_t dalam praktiknya, Anda mungkin bertanya-tanya apa gunanya jika bukan itu.
Maksud dan tujuan asli wchar_t adalah untuk membuat pemrosesan teks sederhana dengan mendefinisikannya sedemikian rupa sehingga memerlukan pemetaan satu-ke-satu dari unit kode string ke karakter teks, sehingga memungkinkan penggunaan algoritme sederhana yang sama seperti yang digunakan dengan string ascii untuk bekerja dengan bahasa lain.
Sayangnya kata-kata spesifikasi wchar_t mengasumsikan pemetaan satu-ke-satu antara karakter dan titik kode untuk mencapai ini. Unicode mematahkan asumsi 2 itu , jadi Anda juga tidak dapat menggunakan wchar_t dengan aman untuk algoritme teks sederhana.
Ini berarti perangkat lunak portabel tidak dapat menggunakan wchar_t baik sebagai representasi umum untuk teks antar lokal, atau untuk mengaktifkan penggunaan algoritme teks sederhana.
Apa gunanya wchar_t hari ini?
Tidak banyak, untuk kode portabel. Jika
__STDC_ISO_10646__
ditentukan maka nilai wchar_t secara langsung mewakili titik kode Unicode dengan nilai yang sama di semua lokal. Itu membuatnya aman untuk melakukan konversi antar-lokal yang disebutkan sebelumnya. Namun Anda tidak dapat hanya mengandalkannya untuk memutuskan bahwa Anda dapat menggunakan wchar_t dengan cara ini karena, sementara sebagian besar platform unix mendefinisikannya, Windows tidak meskipun Windows menggunakan lokal wchar_t yang sama di semua lokal.Alasan Windows tidak menentukan
__STDC_ISO_10646__
adalah karena Windows menggunakan UTF-16 sebagai pengkodean wchar_t, dan karena UTF-16 menggunakan pasangan pengganti untuk merepresentasikan titik kode yang lebih besar dari U + FFFF, yang berarti UTF-16 tidak memenuhi persyaratan untuk__STDC_ISO_10646__
.Untuk kode platform tertentu wchar_t mungkin lebih berguna. Ini pada dasarnya diperlukan di Windows (misalnya, beberapa file tidak dapat dibuka tanpa menggunakan nama file wchar_t), meskipun Windows adalah satu-satunya platform di mana ini benar sejauh yang saya tahu (jadi mungkin kita dapat menganggap wchar_t sebagai 'Windows_char_t').
Melihat ke belakang, wchar_t jelas tidak berguna untuk menyederhanakan penanganan teks, atau sebagai penyimpanan untuk teks independen lokal. Kode portabel tidak boleh mencoba menggunakannya untuk tujuan ini. Kode non-portabel mungkin merasa berguna hanya karena beberapa API memerlukannya.
Alternatif
Alternatif yang saya suka adalah menggunakan string C berenkode UTF-8, bahkan pada platform yang tidak terlalu bersahabat dengan UTF-8.
Dengan cara ini seseorang dapat menulis kode portabel menggunakan representasi teks umum di seluruh platform, menggunakan tipe data standar untuk tujuan yang dimaksudkan, mendapatkan dukungan bahasa untuk jenis tersebut (misalnya string literal, meskipun beberapa trik diperlukan untuk membuatnya berfungsi untuk beberapa kompiler), beberapa dukungan pustaka standar, dukungan debugger (lebih banyak trik mungkin diperlukan), dll. Dengan karakter yang lebar, umumnya lebih sulit atau tidak mungkin untuk mendapatkan semua ini, dan Anda mungkin mendapatkan bagian yang berbeda pada platform yang berbeda.
Satu hal yang tidak disediakan UTF-8 adalah kemampuan untuk menggunakan algoritme teks sederhana seperti yang mungkin dilakukan dengan ASCII. Dalam UTF-8 ini tidak lebih buruk dari pengkodean Unicode lainnya. Sebenarnya ini mungkin dianggap lebih baik karena representasi unit multi-kode dalam UTF-8 lebih umum dan oleh karena itu bug dalam penanganan kode seperti representasi karakter dengan lebar variabel lebih cenderung diperhatikan dan diperbaiki daripada jika Anda mencoba untuk tetap menggunakan UTF -32 dengan NFC atau NFKC.
Banyak platform menggunakan UTF-8 sebagai pengkodean karakter asli mereka dan banyak program tidak memerlukan pemrosesan teks yang signifikan, sehingga menulis program internasionalisasi pada platform tersebut sedikit berbeda dengan menulis kode tanpa mempertimbangkan internasionalisasi. Menulis kode portabel yang lebih luas, atau menulis di platform lain memerlukan penyisipan konversi di batas API yang menggunakan pengkodean lain.
Alternatif lain yang digunakan oleh beberapa perangkat lunak adalah memilih representasi lintas platform, seperti larik pendek unsigned yang menyimpan data UTF-16, dan kemudian menyediakan semua dukungan perpustakaan dan hanya menanggung biaya dalam dukungan bahasa, dll.
C ++ 11 menambahkan jenis karakter lebar baru sebagai alternatif untuk wchar_t, char16_t dan char32_t dengan fitur bahasa / pustaka yang menyertai. Ini sebenarnya tidak dijamin sebagai UTF-16 dan UTF-32, tetapi saya tidak membayangkan implementasi besar apa pun akan menggunakan hal lain. C ++ 11 juga meningkatkan dukungan UTF-8, misalnya dengan literal string UTF-8 sehingga tidak perlu mengelabui VC ++ agar menghasilkan string yang dikodekan UTF-8 (meskipun saya dapat terus melakukannya daripada menggunakan
u8
awalan) .Alternatif untuk dihindari
TCHAR: TCHAR adalah untuk memigrasi program Windows kuno yang mengasumsikan pengkodean lama dari char ke wchar_t, dan paling baik dilupakan kecuali jika program Anda ditulis pada milenium sebelumnya. Ini tidak portabel dan secara inheren tidak spesifik tentang pengkodeannya dan bahkan tipe datanya, membuatnya tidak dapat digunakan dengan API berbasis non-TCHAR. Karena tujuannya adalah migrasi ke wchar_t, yang telah kita lihat di atas bukanlah ide yang baik, tidak ada nilai apa pun dalam menggunakan TCHAR.
1. Karakter yang dapat direpresentasikan dalam string wchar_t tetapi tidak didukung di lokasi mana pun tidak perlu diwakili dengan satu nilai wchar_t. Ini berarti bahwa wchar_t dapat menggunakan pengkodean lebar variabel untuk karakter tertentu, pelanggaran lain yang jelas dari maksud wchar_t. Meskipun dapat diperdebatkan bahwa karakter yang dapat direpresentasikan oleh wchar_t sudah cukup untuk mengatakan bahwa lokal 'mendukung' karakter itu, dalam hal ini pengkodean lebar-variabel tidak legal dan penggunaan UTF-16 oleh Window tidak sesuai.
2. Unicode memungkinkan banyak karakter untuk direpresentasikan dengan beberapa titik kode, yang menciptakan masalah yang sama untuk algoritme teks sederhana seperti pengkodean lebar variabel. Bahkan jika seseorang secara ketat mempertahankan normalisasi yang tersusun, beberapa karakter masih memerlukan banyak titik kode. Lihat: http://www.unicode.org/standard/where/
sumber
fopen
file yang namanya berisi karakter non-ANSI.Tidak ada yang "salah" dengan wchar_t. Masalahnya adalah, pada NT 3.x hari, Microsoft memutuskan bahwa Unicode adalah Bagus (itu), dan menerapkan Unicode sebagai 16-bit, karakter wchar_t. Jadi kebanyakan literatur Microsoft dari pertengahan 90-an cukup banyak menyamakan Unicode == utf16 == wchar_t.
Yang, sayangnya, sama sekali tidak demikian. "Karakter lebar" tidak harus 2 byte, di semua platform, dalam semua keadaan.
Ini adalah salah satu primer terbaik di "Unicode" (terlepas dari pertanyaan ini, terlepas dari C ++) yang pernah saya lihat: Saya sangat merekomendasikannya:
Dan sejujurnya saya percaya bahwa cara terbaik untuk menangani "8-bit ASCII" vs "karakter lebar Win32" vs "wchar_t-in-general" adalah dengan menerima bahwa "Windows Berbeda" ... dan buat kode yang sesuai.
MENURUT OPINI SAYA...
PS:
Saya setuju dengan jamesdlin di atas:
sumber