![]() |
|
![]() ![]() ![]() |
|
zkv |
|
||||||||||||||||||||
![]() ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 2133 Регистрация: 23.7.2006 Где: Санкт-Петербург Репутация: 16 Всего: 92 |
Почему не компилируется программа?
Пожалуй самый часто задаваемый вопрос на 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 байте с латинским и русским(украинским) алфавитом(раскладкой). Автор: takedo Источник: Vingrad Как включить/отключить юникод в проекте. На примере 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. Потому (дополнительно) явные дефайны не рулят - надо знать, что делаем и для чего. Автор: Любитель Источник: Vingrad Преобразование из Unicode в Multi-Byte Проекты у меня всегда Юникод.Но попалась функция.где алгоритм должен был работать с АНСИ строкой. Вот так примерно я сделал.
Автор: Coocky Источник: Vingrad Не понимаю, чего вы паритесь. Строки обоих типов прекрасно друг в друга преобразовываются: у них есть шаблонные конструкторы и операторы присваивания. Вот этот код нормально компилируется и работает:
Конечно, все это правильно насчет WideCharToMultiByte и т.д., но это уже прописано внутри ATL\MFC. Автор: Earnest Источник: Vingrad Это сообщение отредактировал(а) zkv - 24.9.2007, 00:08 |
||||||||||||||||||||
|
|||||||||||||||||||||
JackYF |
|
|||
![]() полуавантюрист ![]() ![]() ![]() ![]() Профиль Группа: Участник Сообщений: 5814 Регистрация: 28.8.2004 Где: страна тысячи озё р Репутация: нет Всего: 162 |
Хороша подборочка
![]() |
|||
|
||||
zkv |
|
|||
![]() ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 2133 Регистрация: 23.7.2006 Где: Санкт-Петербург Репутация: 16 Всего: 92 |
||||
|
||||
akizelokro |
|
|||
![]() Крокодил ![]() ![]() Профиль Группа: Участник Сообщений: 761 Регистрация: 30.7.2007 Репутация: нет Всего: 5 |
Все почти нормально. 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, 09:29 -------------------- a = a + b; b = a - b; a = a - b; |
|||
|
||||
akizelokro |
|
|||
![]() Крокодил ![]() ![]() Профиль Группа: Участник Сообщений: 761 Регистрация: 30.7.2007 Репутация: нет Всего: 5 |
Пример не совсем удачен. Когда я попытался откомпилить этот кусок в 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. Если я как всегда чтой-то не напутал. ![]() -------------------- a = a + b; b = a - b; a = a - b; |
|||
|
||||
zkv |
|
|||
![]() ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 2133 Регистрация: 23.7.2006 Где: Санкт-Петербург Репутация: 16 Всего: 92 |
а не А(1-2 байт)<=W(2 байта) ![]() посмотрю |
|||
|
||||
akizelokro |
|
|||
![]() Крокодил ![]() ![]() Профиль Группа: Участник Сообщений: 761 Регистрация: 30.7.2007 Репутация: нет Всего: 5 |
Ага, напутал. Thanksы.
![]()
Но суть та же SBCS(1 байт), MBCS(1-2 байта), UNICODE(2 байта). -------------------- a = a + b; b = a - b; a = a - b; |
|||
|
||||
akizelokro |
|
|||
![]() Крокодил ![]() ![]() Профиль Группа: Участник Сообщений: 761 Регистрация: 30.7.2007 Репутация: нет Всего: 5 |
Не надо. Уже сам глянул в MSDN. Там идет #include "atlstr.h" и CAtlStringT. Но в примере перевода BSTR через конвертацию посредством C(Atl)StringT вырастают чутка накладные расходы. Хотя, это дело программиста. -------------------- a = a + b; b = a - b; a = a - b; |
|||
|
||||
Ln78 |
|
|||
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 274 Регистрация: 25.11.2006 Репутация: 1 Всего: 15 |
А насколько такая независимость от настроек универсальна?
Например, пишу длл-ку, у экспортируемых функций аргументы THAR. Отдал двоим знакомым, один из них разрабатывает приложение с определённым UNICODE, другой - нет. Неужели обоим повезёт? ![]() |
|||
|
||||
zkv |
|
|||
![]() ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 2133 Регистрация: 23.7.2006 Где: Санкт-Петербург Репутация: 16 Всего: 92 |
Придется создавать две dll'ки, не делай вид что не знаешь ![]() Как это сформулировать-то, проект независимый для времени компиляции. Спасибо за уточнения! Обязательно внесу изменения. Это сообщение отредактировал(а) zkv - 24.9.2007, 13:20 |
|||
|
||||
akizelokro |
|
|||
![]() Крокодил ![]() ![]() Профиль Группа: Участник Сообщений: 761 Регистрация: 30.7.2007 Репутация: нет Всего: 5 |
Достаточно универсальна, если знать, что делать. В VS6 (например), при создании ActiveX контрола у меня появились следующие конфигурации: "win32debug", "win32debug unicode" и тд. Проверить хотя бы на уровне компиляции достаточно просто.
Неграмотное применение невстроенных типов, равно как и предположения о равенстве размера переменных типа int размеру переменных типа long на 64-разрядной платформе, я оставлю на совести программиста. Грабли можно найти и на ровном месте. -------------------- a = a + b; b = a - b; a = a - b; |
|||
|
||||
Ln78 |
|
|||
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 274 Регистрация: 25.11.2006 Репутация: 1 Всего: 15 |
Да я и не делаю, я знал, что ты знаешь, что я знаю ![]() И ещё: раз уж упоминались WideCharToMultiByte и MultiByteToWideChar, то можно сказать "В качстве альтернативы runtime-библиотека C предоставляет более простые, компактные и платформо-независимые функции преобразования" (цитата из Трельсена). Имеются в виду функции wcstombs и mbstowcs |
|||
|
||||
akizelokro |
|
|||
![]() Крокодил ![]() ![]() Профиль Группа: Участник Сообщений: 761 Регистрация: 30.7.2007 Репутация: нет Всего: 5 |
Только в хедерах 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' ![]() -------------------- a = a + b; b = a - b; a = a - b; |
|||
|
||||
Ln78 |
|
|||
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 274 Регистрация: 25.11.2006 Репутация: 1 Всего: 15 |
akizelokro, а ты там же никогда sprintf не компилировал, не видел аналогичного замечания? Вряд ли это имеет самое прямое отношение к char/wchar (хотя тоже новшество студии 2005).
Про хедеры: обычно, когда библиотека распространяется, передаются часть *.h-файлов, *.lib и *.dll. Поэтому я и сказал про хедеры - имея в виду для тех функций, которые являются вызываемыми из других библиотек или приложений. |
|||
|
||||
akizelokro |
|
|||
![]() Крокодил ![]() ![]() Профиль Группа: Участник Сообщений: 761 Регистрация: 30.7.2007 Репутация: нет Всего: 5 |
Ладно, со sprintf почти согласен. Только две поправки. Лучше применять тогда уж вообще snprintf, а в данном конкретном случае _sntprintf, потому что в подобном стиле оформления можно практически полностью избежать конвертации (и тем самым, снять 95% вопроса).
Про хедеры - тоже замётано. Но я уже говорил, тут прежде всего надо знать, что делать. Можно создать проблем другим участникам проекта и без всего, о чем мы говорим. Согласен? -------------------- a = a + b; b = a - b; a = a - b; |
|||
|
||||
![]() ![]() ![]() |
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей) | |
0 Пользователей: | |
« Предыдущая тема | Visual C++/MFC/WTL | Следующая тема » |
|
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности Powered by Invision Power Board(R) 1.3 © 2003 IPS, Inc. |