Локаль по умолчанию.
От: Went  
Дата: 22.10.11 16:47
Оценка:
Здравствуйте. Есть ли какая-то строгая стандартизация того, какая локаль будет активна при старте приложения? Ибо неожиданно для себя получил странное поведение. Винда 7-ка, русская, все настройки стоят русские (в "Языках и Региональных стандартах"). Создаю простейшее Win32-приложение, и выполняю такой код:
const char* ascii_str = "Привет, мир!";
wchar_t wide_str[64];
mbstowcs(wide_str, ascii_str, strlen(ascii_str));

Так вот после этого в буфере wide_str оказываются кракозяблы, и видно, что при конвертации оно использовало CP1252, а не СP1251. Почему?
Re: Локаль по умолчанию.
От: okman Беларусь https://searchinform.ru/
Дата: 22.10.11 17:50
Оценка: 17 (2)
Здравствуйте, 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", и т.п.), так что данный код запросто может выкинуть исключение, будучи
скомпилированным в другом окружении.
Re: Локаль по умолчанию.
От: okman Беларусь https://searchinform.ru/
Дата: 22.10.11 17:57
Оценка: 2 (1)
Здравствуйте, Went.

Предугадывая следующий вопрос: "как же правильно поступить ?", отвечаю — по возможности
всегда использовать только Unicode. Как минимум, отпадут проблемы, связанные с необходимостью
перекодировать текстовое содержимое из одной кодовой страницы в другую.

А если непременно нужно работать с локалями (например, выводить денежные единицы в соответствии с
местными стандартами), то не полагаться на встроенные возможности компилятора (так как они не
стандартизированы) или операционной системы (так как они могут различаться), а задействовать
сторонние библиотеки, специально разработанные для решения подобных задач. Например, ICU.
Re[2]: Локаль по умолчанию.
От: Went  
Дата: 22.10.11 18:35
Оценка:
Здравствуйте, okman, Вы писали:

O>Здравствуйте, Went.


O>Предугадывая следующий вопрос: "как же правильно поступить ?", отвечаю — по возможности

O>всегда использовать только Unicode. Как минимум, отпадут проблемы, связанные с необходимостью
O>перекодировать текстовое содержимое из одной кодовой страницы в другую.

O>А если непременно нужно работать с локалями (например, выводить денежные единицы в соответствии с

O>местными стандартами), то не полагаться на встроенные возможности компилятора (так как они не
O>стандартизированы) или операционной системы (так как они могут различаться), а задействовать
O>сторонние библиотеки, специально разработанные для решения подобных задач. Например, ICU.

Понятно. Спасибо. Да, я использую юникод, но, например, путь к файлу я получаю в ASCII. И получается какая-то ерунда: я могу спокойно открыть файл, использовав это имя, даже если оно будет содержать русские буквы, но безопасно перекодировать это имя в UTF я не могу — локаль по умолчанию не та А как мне установить ту, что мне нужна? Брать язык системы и по нему определять необходимую локаль? Ведь несомненно, это локаль есть!
Re[3]: Локаль по умолчанию.
От: okman Беларусь https://searchinform.ru/
Дата: 23.10.11 08:29
Оценка:
Здравствуйте, Went, Вы писали:

W>Понятно. Спасибо. Да, я использую юникод, но, например, путь к файлу я получаю в ASCII. И получается какая-то ерунда: я могу спокойно открыть файл, использовав это имя, даже если оно будет содержать русские буквы, но безопасно перекодировать это имя в UTF я не могу — локаль по умолчанию не та А как мне установить ту, что мне нужна?Брать язык системы и по нему определять необходимую локаль? Ведь несомненно, это локаль есть!


Перекодировать можно.
Для этого, во-первых, можно воспользоваться функцией MultiByteToWideChar из Win32 API, либо
задать локаль явно, при помощи std::locale::global или setlocale, или даже использовать аналог
mbstowcs — функцию _mbstowcs_l, у которой есть параметр для задания локали.
Кстати, в MSDN-овском описании функции setlocale перечисляются допустимые строковые
литералы для ее определения, которые поддерживается средой Visual C++.
Так что не все так безнадежно. Ну и повторюсь, есть еще библиотеки, которые с данной
задачей справляются на высшем уровне.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.