Тут є кілька дуже хороших відповідей, але я думаю, що я можу додати кілька речей щодо Windows / Visual Studio. Це засновано на моєму досвіді роботи з VS2015. В Linux в основному відповідь полягає в тому, щоб використовувати UTF-8, закодовані std::string
скрізь. У Windows / VS він стає складнішим. Ось чому. Windows очікує, що рядки, збережені за допомогою char
s, будуть кодовані за допомогою локальної кодової сторінки. Це майже завжди набір символів ASCII, а за ним - 128 інших спеціальних символів, залежно від вашого місцезнаходження. Дозвольте лише зазначити, що це не лише при використанні API Windows, є три інші основні місця, де ці рядки взаємодіють зі стандартним C ++. Це рядкові літерали, вихідні дані з std::cout
використанням <<
та передача імені файлу std::fstream
.
Я буду тут наперед, що я програміст, а не мовний фахівець. Я розумію, що USC2 та UTF-16 не однакові, але для моїх цілей вони досить близькі, щоб бути взаємозамінними, і я їх тут використовую як таких. Я насправді не впевнений, яку Windows використовує, але мені взагалі не потрібно знати. У цій відповіді я заявив про UCS2, тому заздалегідь вибачте, якщо я засмутив когось своїм незнанням цього питання, і я радий змінити його, якщо у мене щось не так.
Строкові літерали
Якщо ви вводите рядкові літерали, що містять лише символи, які можуть бути представлені вашою кодовою сторінкою, тоді VS зберігає їх у вашому файлі з 1 байтом на кодування символів на основі вашої кодової сторінки. Зауважте, що якщо ви зміните свою кодову сторінку або надаєте джерело іншому розробнику, використовуючи іншу кодову сторінку, то я думаю (але не перевіряв), що символ у кінцевому підсумку буде іншим. Якщо ви запускаєте свій код на комп’ютері, використовуючи іншу кодову сторінку, то я не впевнений, чи зміниться також символ.
Якщо ви введете будь-які рядкові літерали, які не можуть бути представлені вашою кодовою сторінкою, тоді VS попросить вас зберегти файл як Unicode. Потім файл буде кодуватися як UTF-8. Це означає, що всі символи, що не належать до ASCII (включаючи ті, що знаходяться на вашій кодовій сторінці) будуть представлені 2 або більше байтами. Це означає, що якщо ви дасте джерело комусь іншому, джерело буде виглядати так само. Однак, перш ніж передавати джерело компілятору, VS перетворює закодований текст UTF-8 у закодований текст кодової сторінки, а будь-які символи, відсутніх на кодовій сторінці, замінюються ?
.
Єдиний спосіб гарантувати правильне представлення літерального рядка Unicode у VS - це передувати рядковому літралу, L
зробивши його широким літеральним рядком. У цьому випадку VS перетворить закодований текст UTF-8 з файлу в UCS2. Потім вам потрібно передати цей рядковий буквал в std::wstring
конструктор або вам потрібно перетворити його в utf-8 і поставити його в a std::string
. Або якщо ви хочете, ви можете використовувати функції API Windows, щоб кодувати її за допомогою кодової сторінки, щоб поставити її вstd::string
, але тоді ви, можливо, також не використали широкий рядковий літерал.
std :: cout
При виведенні на консоль за допомогою <<
ви можете використовувати тільки std::string
, а не, std::wstring
а текст повинен бути закодований за допомогою вашої локальної кодової сторінки. Якщо у вас є, std::wstring
ви повинні перетворити його за допомогою однієї з функцій API Windows, а будь-які символи, які не знаходяться на кодовій сторінці, замінюються на?
(можливо, ви можете змінити символ, я не можу згадати).
std :: файлові файли fstream
ОС Windows використовує UCS2 / UTF-16 для своїх імен файлів, тому незалежно від кодової сторінки, ви можете мати файли з будь-яким символом Unicode. Але це означає, що для доступу або створення файлів з символами, які не знаходяться на кодовій сторінці, ви повинні використовувати std::wstring
. Іншого шляху немає. Це розширення для Microsoft, яке, std::fstream
можливо, не компілюється в інших системах. Якщо ви використовуєте std :: string, ви можете використовувати лише назви файлів, які містять лише символи на вашій кодовій сторінці.
Ваші варіанти
Якщо ви просто працюєте на Linux, то, ймовірно, цього не досягли. Просто використовуйте UTF-8 std::string
скрізь.
Якщо ви просто працюєте в Windows, просто використовуйте UCS2 std::wstring
скрізь. Деякі пуристи можуть сказати, що використовувати UTF8, а потім конвертувати, коли це потрібно, але навіщо турбуватися із клопотами.
Якщо ви є крос-платформою, то це буде безладдя відверто. Якщо ви намагаєтесь використовувати UTF-8 скрізь у Windows, то вам потрібно бути дуже обережними зі своїми рядковими літералами та виводити на консоль. Ви можете легко зіпсувати там свої струни. Якщо ви використовуєте std::wstring
всюди в Linux, ви, можливо, не маєте доступу до широкої версії std::fstream
, тому вам доведеться зробити конверсію, але немає ризику пошкодження. Тож особисто я думаю, що це кращий варіант. Багато хто не погодиться, але я не самотній - це, наприклад, шлях wxWidgets.
Іншим варіантом може бути введенняdedef, unicodestring
як std::string
у Linux та std::wstring
Windows, і мати макрос під назвою UNI (), який має префікси L в Windows, а нічого в Linux, а потім код
#include <fstream>
#include <string>
#include <iostream>
#include <Windows.h>
#ifdef _WIN32
typedef std::wstring unicodestring;
#define UNI(text) L ## text
std::string formatForConsole(const unicodestring &str)
{
std::string result;
//Call WideCharToMultiByte to do the conversion
return result;
}
#else
typedef std::string unicodestring;
#define UNI(text) text
std::string formatForConsole(const unicodestring &str)
{
return str;
}
#endif
int main()
{
unicodestring fileName(UNI("fileName"));
std::ofstream fout;
fout.open(fileName);
std::cout << formatForConsole(fileName) << std::endl;
return 0;
}
Було б добре на будь-якій платформі, я думаю.
Відповіді
Отже, щоб відповісти на ваші запитання
1) Якщо ви програмуєте для Windows, то весь час, якщо крос-платформа, то, можливо, весь час, якщо ви не хочете мати справу з можливими корупційними проблемами в Windows або написати якийсь код з платформою, специфічною #ifdefs
для вирішення відмінностей, якщо просто використовувати Тоді Linux ніколи.
2) Так. Крім Linux, ви можете використовувати його і для всіх Unicode. У Windows ви можете використовувати його для всіх unicode, лише якщо ви вирішите кодувати вручну за допомогою UTF-8. Але Windows API і стандартні класи C ++ очікують, що std::string
вони будуть закодовані за допомогою локальної кодової сторінки. Сюди входять усі ASCII та ще 128 символів, які змінюються залежно від кодової сторінки, на яку налаштовано ваш комп'ютер.
3) Я так вважаю, але якщо ні, то це просто простий typedef 'std :: basic_string', який використовує wchar_t
замістьchar
4) Широкий символ - це тип символів, який більший за стандартний char
тип на 1 байт . У Windows це 2 байти, в Linux - 4 байти.