Программирование на Visual C++. Архив рассылки
Шрифт:
Отдельной "увлекательной" стадией сборки приложения является поиск функции или фрагмента кода, вызвавшего такую ситуацию. Для этого применяются следующие шаги:
• Включается опция компоновщика /verbose, при которой он выдает значительно большее количество диагностической информации.
• Включается опция компоновщика /nodefaultlib (или /nod), которая подавляет при сборке поиск библиотек, кроме указанных явно. При этом в списке неразрешенных внешних ссылок будут как "безобидные" функции CRT (которые можно будет включить явно), так и "тянущие" за собой стартовый код CRT.
• Локализовав модуль или функцию проекта,
А как же насчет Standard Template Library (STL)? Насколько она завязана на CRT, можно ли использовать её в сверхмалых проектах?
Реализация STL от Dinkumware, поставляемая вместе с VC 5.0 и 6.0, доступна в исходных файлах, так что проблем с компоновкой не возникает. В крайнем случае, всегда можно исправить исходники или сделать какую-нибудь заглушку на #define'ах (перебивающую имена конструкций, тянущих за собой CRT). Другая проблема – в том, что STL повсеместно использует операторы динамического выделения памяти. Как уже говорилось, это вызывает необходимость собственной реализации операторов new/delete. Это можно сделать, например, так (идея позаимствована из atlimpl.cpp):
Вот пример программы, которая будет спокойно собрана с помощью такого подхода без стартового кода CRT:
Для
Библиотека импорта kernel32.lib необходима для функций работы с Win32-кучей.
Что касается других реализаций STL, предоставлю слово Павлу Блудову:
Страшная тайна STL от SGI и HP в том, что им совершенно не нужна CRT.
С двумя оговорками:
1. Не используется C++ Exception Handling
2. (Вытекает из первой) определен макрос __THROW_BAD_ALLOC, например, так:
если посмотреть на __THROW_BAD_ALLOC, то он являет собой
#define __THROW_BAD_ALLOCfprintf(stderr, "out of memory\n"); exit(1)
именно эта строчка, и никакая другая, нуждается в CRT. Ну, если быть совсем точным, std::string'у может понадобиться CRT. Тут уж ничего не попишешь. Используйте WTL::CString.
Слова о std::string в полной мере справедливы и для реализации STL от Dinkumware. Если вы ищете реализацию полноценного строкового класса, не использующего стартовый код CRT, советую взглянуть на CascString в составе библиотеки ascLib.
Частой причиной появления зависимости от CRT является необдуманное применение директивы #import – расширения visual c++ для удобства работы с COM-объектами, предоставляющими библиотеки типов. Подробнее о ней можно прочитать в MSDN, а на русском языке – в статье Игоря Ткачева "Использование директивы #import в Visual C++".
При ее использовании компилятор генерирует описания интерфейсов и, если не указано обратное, создает набор оберточных классов (wrappers) для упрощения работы с указателями на эти интерфейсы. Кроме того, детали реализации COM-объектов скрываются за высокоуровневыми средствами. В число таких деталей входят преобразование [out,retval]-параметров в возвращаемые значения функций, упрощение работы с BSTR-строками, управление сроками жизни объектов, доступ к свойствам и преобразование COM-HRESULT в исключения C++. Но поддержка всех этих приятных "мелочей" реализована с использованием CRT и требует включения стартового кода CRT.
Директива #import, несомненно, полезна для C++-программиста – ведь иначе, не имея описания интерфейсов, пришлось бы извлекать необходимую информацию вручную с помощью утилит типа OleView. Эту директиву можно применять и в проектах, не использующих CRT, но с рядом ограничений. В частности, необходимо подавить создание оберточных классов и трансляцию типов COM в классы-обертки _com_ptr, _com_error, _variant_t и _bstr_t. Вот пример выверенного использования #import, которое не "потянет" за собой половину кода CRT: