Здравствуйте. Есть ли какая-то строгая стандартизация того, какая локаль будет активна при старте приложения? Ибо неожиданно для себя получил странное поведение. Винда 7-ка, русская, все настройки стоят русские (в "Языках и Региональных стандартах"). Создаю простейшее Win32-приложение, и выполняю такой код:
const char* ascii_str = "Привет, мир!";
wchar_t wide_str[64];
mbstowcs(wide_str, ascii_str, strlen(ascii_str));
Так вот после этого в буфере wide_str оказываются кракозяблы, и видно, что при конвертации оно использовало CP1252, а не СP1251. Почему?
Здравствуйте, Went, Вы писали:
W>Здравствуйте. Есть ли какая-то строгая стандартизация того, какая локаль будет активна при старте приложения?
Стандартом гарантируется только одна локализация.
Это так называемая C-локализация — она использует ASCII-коды для символов и американские
стандарты написания денежных единиц, дат и тому подобного. Она же устанавливается при
запуске приложения. Реализовывать другие локализации стандарт не требует.
W>Ибо неожиданно для себя получил странное поведение. Винда 7-ка, русская, все настройки стоят русские (в "Языках и Региональных стандартах"). Создаю простейшее Win32-приложение, и выполняю такой код:
W>W>const char* ascii_str = "Привет, мир!";
W>wchar_t wide_str[64];
W>mbstowcs(wide_str, ascii_str, strlen(ascii_str));
W>
W>Так вот после этого в буфере wide_str оказываются кракозяблы, и видно, что при конвертации оно использовало CP1252, а не СP1251. Почему?
Потому что mbstowcs использует текущую локализацию, о чем и сказано в документации к этой функции.
Тот результат, который Вы хотите получить, достигается примерно так:
#include <iostream>
#include <locale>
int main()
{
std::locale Locale("russian");
std::locale::global(Locale);
char const *pString = "Привет, мир!";
wchar_t Buffer[64];
mbstowcs(Buffer, pString, strlen(pString) + 1);
std::wcout << Buffer << std::endl;
return 0;
}
// >Привет, мир!
Но учтите, что обеспечение локализаций для других языков и регионов стандартом не требуются и
даже их названия могут отличаться на разных компиляторах ("russian", "ru_RU",
"russian_RU.CP1251", и т.п.), так что данный код запросто может выкинуть исключение, будучи
скомпилированным в другом окружении.
Здравствуйте, Went.
Предугадывая следующий вопрос: "как же правильно поступить ?", отвечаю — по возможности
всегда использовать только Unicode. Как минимум, отпадут проблемы, связанные с необходимостью
перекодировать текстовое содержимое из одной кодовой страницы в другую.
А если непременно нужно работать с локалями (например, выводить денежные единицы в соответствии с
местными стандартами), то не полагаться на встроенные возможности компилятора (так как они не
стандартизированы) или операционной системы (так как они могут различаться), а задействовать
сторонние библиотеки, специально разработанные для решения подобных задач. Например,
ICU.
Здравствуйте, okman, Вы писали:
O>Здравствуйте, Went.
O>Предугадывая следующий вопрос: "как же правильно поступить ?", отвечаю — по возможности
O>всегда использовать только Unicode. Как минимум, отпадут проблемы, связанные с необходимостью
O>перекодировать текстовое содержимое из одной кодовой страницы в другую.
O>А если непременно нужно работать с локалями (например, выводить денежные единицы в соответствии с
O>местными стандартами), то не полагаться на встроенные возможности компилятора (так как они не
O>стандартизированы) или операционной системы (так как они могут различаться), а задействовать
O>сторонние библиотеки, специально разработанные для решения подобных задач. Например, ICU.
Понятно. Спасибо. Да, я использую юникод, но, например, путь к файлу я получаю в ASCII. И получается какая-то ерунда: я могу спокойно открыть файл, использовав это имя, даже если оно будет содержать русские буквы, но безопасно перекодировать это имя в UTF я не могу — локаль по умолчанию не та

А как мне установить ту, что мне нужна? Брать язык системы и по нему определять необходимую локаль? Ведь несомненно, это локаль есть!
Здравствуйте, Went, Вы писали:
W>Понятно. Спасибо. Да, я использую юникод, но, например, путь к файлу я получаю в ASCII. И получается какая-то ерунда: я могу спокойно открыть файл, использовав это имя, даже если оно будет содержать русские буквы, но безопасно перекодировать это имя в UTF я не могу — локаль по умолчанию не та
А как мне установить ту, что мне нужна?Брать язык системы и по нему определять необходимую локаль? Ведь несомненно, это локаль есть!
Перекодировать можно.
Для этого, во-первых, можно воспользоваться функцией MultiByteToWideChar из Win32 API, либо
задать локаль явно, при помощи std::locale::global или setlocale, или даже использовать аналог
mbstowcs — функцию _mbstowcs_l, у которой есть параметр для задания локали.
Кстати, в MSDN-овском описании функции setlocale перечисляются допустимые строковые
литералы для ее определения, которые поддерживается средой Visual C++.
Так что не все так безнадежно. Ну и повторюсь, есть еще библиотеки, которые с данной
задачей справляются на высшем уровне.