Що таке wchar_t?
wchar_t визначається таким чином, що кодування символу будь-якої локалі може бути перетворено у представлення wchar_t, де кожен wchar_t представляє рівно одну кодову точку:
Тип wchar_t - це окремий тип, значення якого можуть представляти різні коди для всіх членів найбільшого розширеного набору символів, зазначеного серед підтримуваних локалей (22.3.1).
- C ++ [basic.fundamental] 3.9.1 / 5
Для цього не потрібно, щоб wchar_t був достатньо великим, щоб одночасно представляти будь-який символ із усіх мов. Тобто, кодування, яке використовується для wchar_t, може відрізнятися в різних регіонах. Це означає, що ви не можете обов'язково перетворити рядок у wchar_t, використовуючи одну локаль, а потім перетворити назад у char, використовуючи іншу локаль. 1
Оскільки використання wchar_t як загального представлення між усіма локалями, здається, є основним використанням wchar_t на практиці, ви можете замислитися, для чого це добре, якщо не це.
Початковий намір і мета wchar_t полягав у спрощенні обробки тексту, визначаючи її таким чином, що вона вимагає однозначного зіставлення з кодових одиниць рядка на символи тексту, дозволяючи тим самим використовувати ті самі прості алгоритми, що використовуються за допомогою рядків ascii для роботи з іншими мовами.
На жаль, формулювання специфікації wchar_t передбачає індивідуальне відображення символів та кодових точок для досягнення цього. Юнікод порушує це припущення 2 , тому ви також не можете безпечно використовувати wchar_t для простих текстових алгоритмів.
Це означає, що портативне програмне забезпечення не може використовувати wchar_t ні як загальне представлення тексту між локалями, ні для того, щоб дозволити використання простих текстових алгоритмів.
Яка користь від wchar_t сьогодні?
Не багато, для портативного коду в будь-якому випадку. Якщо __STDC_ISO_10646__
визначено, тоді значення wchar_t безпосередньо представляють кодові точки Unicode з однаковими значеннями у всіх регіонах. Це робить безпечним перетворення міжлокальних перетворень, про які згадувалося раніше. Однак ви не можете покластися лише на це, щоб вирішити, що ви можете використовувати wchar_t таким чином, оскільки, хоча більшість платформ unix це визначають, Windows не використовує, хоча Windows використовує однакову локаль wchar_t у всіх локалях.
Причина, яку Windows не визначає, __STDC_ISO_10646__
полягає в тому, що Windows використовує UTF-16 як кодування wchar_t, і тому, що UTF-16 використовує сурогатні пари для представлення кодових точок, більших за U + FFFF, а це означає, що UTF-16 не задовольняє вимогам __STDC_ISO_10646__
.
Для певного коду платформи wchar_t може бути кориснішим. По суті, це потрібно для Windows (наприклад, деякі файли просто неможливо відкрити без використання імен файлів wchar_t), хоча Windows є єдиною платформою, де це відповідає дійсності, наскільки мені відомо (тому, можливо, ми можемо думати про wchar_t як про "Windows_char_t").
З огляду на те, wchar_t явно не корисний для спрощення обробки тексту або як сховище для тексту, незалежного від мови. Портативний код не повинен намагатися використовувати його для цих цілей. Непортативний код може виявитися корисним просто тому, що це вимагає якийсь API.
Альтернативи
Альтернатива, яка мені подобається, - це використання кодованих рядків C UTF-8, навіть на платформах, не особливо зручних для UTF-8.
Таким чином можна писати переносний код, використовуючи загальне текстове представлення на платформах, використовувати стандартні типи даних за прямим призначенням, отримувати підтримку мови для цих типів (наприклад, рядкові літерали, хоча деякі трюки необхідні, щоб це працювало для деяких компіляторів), деякі підтримка стандартної бібліотеки, підтримка налагоджувача (може знадобитися більше хитрощів) тощо. З широкими символами, як правило, важче або неможливо отримати все це, і ви можете отримати різні шматки на різних платформах.
Одна річ, яку UTF-8 не забезпечує, - це можливість використовувати прості текстові алгоритми, такі як можливі з ASCII. У цьому UTF-8 не гірше, ніж будь-яке інше кодування Unicode. Насправді це можна вважати кращим, оскільки мультикодові одиничні подання в UTF-8 є більш поширеними, тому помилки в коді, що обробляють такі подання змінної ширини символів, швидше за все будуть помічені та виправлені, ніж якщо ви намагаєтесь дотримуватися UTF -32 з NFC або NFKC.
Багато платформ використовують UTF-8 як своє власне кодування символів, і багато програм не вимагають значної обробки тексту, і тому написання інтернаціоналізованої програми на цих платформах мало чим відрізняється від написання коду без урахування інтернаціоналізації. Написання ширшого портативного коду або написання на інших платформах вимагає вставки перетворень на межі API, які використовують інші кодування.
Ще однією альтернативою, яку використовує деяке програмне забезпечення, є вибір міжплатформенного представлення, наприклад, неподписані короткі масиви, що містять дані UTF-16, а потім надання всієї бібліотечної підтримки і просто задоволення витратами на підтримку мови тощо.
C ++ 11 додає нові види широких символів як альтернативу wchar_t, char16_t та char32_t із супутніми функціями мови / бібліотеки. Насправді це не гарантовано UTF-16 та UTF-32, але я не думаю, що будь-яка велика реалізація буде використовувати щось інше. C ++ 11 також покращує підтримку UTF-8, наприклад, з рядковими літералами UTF-8, тому не буде потрібно обманювати VC ++ у створенні кодованих рядків UTF-8 (хоча я можу продовжувати це робити, а не використовувати u8
префікс) .
Альтернативи, яких слід уникати
TCHAR: TCHAR призначений для міграції старовинних програм Windows, які передбачають застарілі кодування від char до wchar_t, і про це найкраще забути, якщо ваша програма не була написана в якомусь попередньому тисячолітті. Він не є портативним і за своєю суттю неспецифічний щодо свого кодування і навіть типу даних, що робить його непридатним для використання з будь-яким API, що не базується на TCHAR. Оскільки його метою є перехід на wchar_t, що, як ми вже бачили вище, не є гарною ідеєю, використання TCHAR абсолютно не має значення.
1. Символи, які можна представити в рядках wchar_t, але які не підтримуються в будь-якій мові, не повинні бути представлені одним значенням wchar_t. Це означає, що wchar_t може використовувати кодування змінної ширини для певних символів, ще одне явне порушення наміру wchar_t. Хоча можна сперечатися з тим, що символ, який може бути представлений wchar_t, достатньо, щоб сказати, що локаль `` підтримує '' цей символ, і в цьому випадку кодування змінної ширини не є законним, а використання Window UTF-16 не відповідає.
2. Юнікод дозволяє представляти багато символів із декількома кодовими точками, що створює ті самі проблеми для простих текстових алгоритмів, що і кодування змінної ширини. Навіть якщо чітко дотримуватися складеної нормалізації, для деяких символів все одно потрібні кілька кодових точок. Див .: http://www.unicode.org/standard/where/