| Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате |
| Форум программистов > Visual C++/MFC/WTL > Настройки Unicode и Multi-Byte в MFC-проекте. Или почему не компилируется программа? |
| Автор: zkv 24.9.2007, 00:02 | ||||||||||||||||||||
| Почему не компилируется программа? Пожалуй самый часто задаваемый вопрос на MFC-форуме выглядит примерно так:
Дело в том, что у вас в настройках проекта установлена опция "Use Unicode Character Set", а вы пытаетесь использовать неюникодную строку: "Text" Существуют следующие варианты решения: 1. Отключить юникод в проекте. Самый простой, но идеологически неправильный путь. Когда-нибудь может выйти боком. 2. Использовать юникодные строки. Правильный путь, но следующий лучше. 3. Сделать код в проекте независимым от настроек юникода. Самый верный путь. В чем отличия Unicode Multi-Byte? простыми словами: UniCode - на символ 2 байта, в MultiByte - 1 байт. Как известно в 1 байте 8 бит. Каждый бит может быть либо 0 либо 1 по определению. И это двоичное исчисление. Следовательно, ты можешь из 8 бит получить 2 в 8 степени комбинаций, то есть 256. А в двух байтах комбинаций 65536. Соответственно любимый всеми албанский язык может не поместиться в 256-ти комбинациях вместе с латинским-английским. А что говорить об иероглифах? Вот и сделали 2 байта - должно хватать всем. Сам понимаешь, что из одного байта ты с большей вероятностью перейдешь без потери информативности в два байта, чем обратно. Следовательно, для того, чтобы программы твои могли ходить по всему миру - работай в Unicode (надо то всего лишь галочку поставить). Вот и у тебя в подписи какая то строка из трех иероглифов - как они уживутся в 1 байте с латинским и русским(украинским) алфавитом(раскладкой). Автор: http://vingrad.ru/@takedo Источник: http://forum.vingrad.ru/index.php?show_type=forum&showtopic=134403 Как включить/отключить юникод в проекте. На примере Visual C++ 8.0 (входит в состав Microsoft Visual Studio 2005). В главном меню находим "Project", заходим в <имя_вышего_проекта> properties... либо жмем Alt+F7. Появляется диалог настроек проекта, раскрываем ветку Configuration Properties->General (для более ранних версий студии просто General), ищем строку Charaster Set, выбираем для нее значение Use Multi-Byte charaster Set, для отключения юникода и, соответственно, Use Unicode charaster Set для включения. Использование юникодных строк. Правильнее говорить строковые литералы, но не суть. Строка Multi-Byte задается, как вы уже наверное знаете, так:
юникодная строка так:
те для приведенного выше примера подойдет такая запись:
Сделать код в проекте независимым от настроек юникода Для этого нужно обернуть все строки макросом _T() или TEXT(), а в качестве типа, представляющего отдельный символ использовать TCHAR. Пример:
те для приведенного выше примера подойдет такая запись: SetWindowText( _T("Text") ); Теперь компилятор, в зависимости от настроек проекта интерпретирует строку правильно, то есть если юникод включен то как L"Text", а если выключен, то как "Text", а тип TCHAR будет понят как WCHAR или CHAR соответственно. Тоже касается типа LPTSTR, который разворачивается в LPWSTR либо LPSTR Практически для всех функций, принимающих строки в качестве аргументов существует два варианта - с буквами A и W на конце, также существуют соответствующие макросы котрые разворачиваются в один из вариантов в зависимости от настроек юникода. К примеру существуют функции: SetWindowTextA SetWindowTextW и макрос: SetWindowText, который будет интерпретирован компилятором как один из вариантов выше. Вывод: если делаете код независимым от настроек юникода, используйте имена функций без A и W на конце, иначе вы только запутываете себя и окружающих. Посмотрим что получается в нашем примере:
если юникод включен, то он воспринимается компилятором, как если было бы написано:
если юникод выключен, то как:
чего мы и добивались - проект будет компилироваться в любом случае. Следует только добавить, что для функций из Microsoft run-time library тоже существует по три вида на каждую, только зная один из видов не всегда легко догадаться, какие остальные два вида. Для printf() например, подборка такая: _tprintf - для TCHAR printf - для CHAR wprintf - для WCHAR для юникодо-независимого кода нужно использовать _tprintf. чтобы узнать вид TCHAR'ного эквивалента для конкретной функции пользуйтесь MSDN (печатаем printf, ставим на него курсор, жмем F1). Отличия макросов _T() и TEXT() отличие очень тонкое. У MS есть два макроса для юникода/неюникода: 1. UNCIDOE - PSDK (Platform SDK - Windows SDK) для WinAPI функций. 2. _UNICODE- в CRT (C Runtime) для всяких _tprintf, _tcsclen и пр. Для первого в winnt.h определяется макрос TEXT, именно он рекомендуется к использованию (так как фнукциями WinAPI пользуются чаще, хотя правда вряд ли кто-то будет определять юникод для одного и запрещать для другого Вот так. Когда в пропертях проекта ставим юникод - в команд-лайн компилера добавляется /DUNICODE и /D_UNICODE. Потому (дополнительно) явные дефайны не рулят - надо знать, что делаем и для чего. Автор: http://vingrad.ru/@Любитель Источник: http://forum.vingrad.ru/index.php?show_type=forum&showtopic=147226 Преобразование из Unicode в Multi-Byte Проекты у меня всегда Юникод.Но попалась функция.где алгоритм должен был работать с АНСИ строкой. Вот так примерно я сделал.
Автор: http://vingrad.ru/@Coocky Источник: http://forum.vingrad.ru/index.php?show_type=forum&showtopic=164907 Не понимаю, чего вы паритесь. Строки обоих типов прекрасно друг в друга преобразовываются: у них есть шаблонные конструкторы и операторы присваивания. Вот этот код нормально компилируется и работает:
Конечно, все это правильно насчет WideCharToMultiByte и т.д., но это уже прописано внутри ATL\MFC. Автор: http://vingrad.ru/@Earnest Источник: http://forum.vingrad.ru/index.php?show_type=forum&showtopic=164907 |
| Автор: JackYF 24.9.2007, 00:56 |
| Хороша подборочка |
| Автор: zkv 24.9.2007, 01:05 |
лучше критику давай |
| Автор: akizelokro 24.9.2007, 09:25 |
| Все почти нормально. MBCS - не один байт, а от 1 до 2. Для работы с std::string рекомендуется в статье на codeproject.com что-то подобное typedef std::basic_string<TCHAR> tstring; так что std::string(std::wstring) объявляются tstring s;// пример объявления там же прописываются разные виды win-строковых типов, а также примеры работы и преобразований (где есть сложности), а также как прописывать _T-функции (аналоги стандартной С-библиотеки для работы с строками). вместо char c = *i; рекомендуется TCHAR c = ... Статья в двух частях, прочитать стоит. Ссылку прямо щас не найду. |
| Автор: akizelokro 24.9.2007, 10:14 | ||
Пример не совсем удачен. Когда я попытался откомпилить этот кусок в ATL-проекте (без MFC) компилер выдал: C:\Program Files\Microsoft Visual Studio 9.0\VC\atlmfc\include\afx.h(24) : fatal error C1189: #error : Building MFC application with /MD[d] (CRT dll version) requires MFC shared dll version. Please #define _AFXDLL or do not use /MD[d] Это во-первых. Во-вторых, более показателен был бы пример с последовательностью CStringA strA(strW), так как А(1 байт)<=W(1-2 байта). Но и здесь задача еще является достаточно упрощенной. Более сложный вариант был бы по конвертации BSTR (в Юникодовском проекте) в std::string. И здесь уже надо применять ATL-вское USES_CONVERSION; SetDlgItemText(IDC_EDIT1, W2CT(bstr)); или wctomb. Если я как всегда чтой-то не напутал. |
| Автор: akizelokro 24.9.2007, 10:55 | ||
Ага, напутал. Thanksы.
Но суть та же SBCS(1 байт), MBCS(1-2 байта), UNICODE(2 байта). |
| Автор: akizelokro 24.9.2007, 11:12 | ||
Не надо. Уже сам глянул в MSDN. Там идет #include "atlstr.h" и CAtlStringT. Но в примере перевода BSTR через конвертацию посредством C(Atl)StringT вырастают чутка накладные расходы. Хотя, это дело программиста. |
| Автор: Ln78 24.9.2007, 13:06 |
| А насколько такая независимость от настроек универсальна? Например, пишу длл-ку, у экспортируемых функций аргументы THAR. Отдал двоим знакомым, один из них разрабатывает приложение с определённым UNICODE, другой - нет. Неужели обоим повезёт? |
| Автор: zkv 24.9.2007, 13:18 | ||
Придется создавать две dll'ки, не делай вид что не знаешь Как это сформулировать-то, проект независимый для времени компиляции. Спасибо за уточнения! Обязательно внесу изменения. |
| Автор: akizelokro 24.9.2007, 13:36 |
| Достаточно универсальна, если знать, что делать. В VS6 (например), при создании ActiveX контрола у меня появились следующие конфигурации: "win32debug", "win32debug unicode" и тд. Проверить хотя бы на уровне компиляции достаточно просто. Неграмотное применение невстроенных типов, равно как и предположения о равенстве размера переменных типа int размеру переменных типа long на 64-разрядной платформе, я оставлю на совести программиста. Грабли можно найти и на ровном месте. |
| Автор: Ln78 24.9.2007, 13:59 |
Да я и не делаю, я знал, что ты знаешь, что я знаю И ещё: раз уж упоминались WideCharToMultiByte и MultiByteToWideChar, то можно сказать "В качстве альтернативы runtime-библиотека C предоставляет более простые, компактные и платформо-независимые функции преобразования" (цитата из Трельсена). Имеются в виду функции wcstombs и mbstowcs |
| Автор: akizelokro 24.9.2007, 14:49 | ||
Только в хедерах TCHAR не пишем? С wcstombs тоже не все так уж гладко. Я в бета-релизе откомпилил такое: Code.cpp(177) : warning C4996: 'wcstombs': This function or variable may be unsafe. Consider using wcstombs_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details. C:\Program Files\Microsoft Visual Studio 9.0\VC\include\stdlib.h(534) : see declaration of 'wcstombs' |
| Автор: Ln78 24.9.2007, 15:09 |
| akizelokro, а ты там же никогда sprintf не компилировал, не видел аналогичного замечания? Вряд ли это имеет самое прямое отношение к char/wchar (хотя тоже новшество студии 2005). Про хедеры: обычно, когда библиотека распространяется, передаются часть *.h-файлов, *.lib и *.dll. Поэтому я и сказал про хедеры - имея в виду для тех функций, которые являются вызываемыми из других библиотек или приложений. |
| Автор: akizelokro 25.9.2007, 07:06 |
| Ладно, со sprintf почти согласен. Только две поправки. Лучше применять тогда уж вообще snprintf, а в данном конкретном случае _sntprintf, потому что в подобном стиле оформления можно практически полностью избежать конвертации (и тем самым, снять 95% вопроса). Про хедеры - тоже замётано. Но я уже говорил, тут прежде всего надо знать, что делать. Можно создать проблем другим участникам проекта и без всего, о чем мы говорим. Согласен? |
| Автор: zkv 25.9.2007, 10:28 |
| Предлагаю sprintf больше не обсуждать По поводу хедеров, по мне удобнее когда хедеры одни и теже в библиотеке, а отличаются только либ-файлы и длл, опять таки, достаточно изменить пару настроек в проекте - и все работает в другом charaster set. Причем многие библиотеки так и поступают. И если что линкер либу не пропустит неправильную (если не голая дллка, конечно). Корректировки внесу скоро. |