Чтение онлайн

на главную - закладки

Жанры

Программирование на Visual C++. Архив рассылки

Jenter Алекс

Шрифт:

И да, и нет. Опция компилятора /MD указывает использовать для сборки библиотеку MSVCRT.LIB. В ней содержится только тот набор кода, который позволяет линкеру разрешить внешние связи. А сам код CRT находится в динамической библиотеке MSVCRT.DLL в системном каталоге windows. Эта многопоточная библиотека используется и некоторыми бесплатными компиляторами C/C++ для Windows, например, MinGW.

Такое решение достаточно удобно, если проект состоит из нескольких модулей – каждый из них станет меньше на объем рантайма. Кроме того, оно позволяет Microsoft исправлять ошибки в уже выпущенных программах простой заменой старой DLL на исправленную версию.

Этот подход активно используется многими разработчиками, использующими библиотеку MFC: если в опциях проекта выбрать "Use MFC in a shared DLL", то придется использовать динамическую версию CRT, иначе проект попросту не соберется. В интегрированной среде версия CRT выбирается в свойствах проекта: на закладке C/C++ в категории Code Generation.

Плохая новость заключается в том, что MSVCRT.DLL существует не на всех версиях Windows. Она начала поставляться в составе ОС, начиная с Windows 95 OSR2. Приложение, запущенное в системе без этой библиотеки, выполняться не будет. Правда, таких систем становится все меньше и меньше.

Уменьшение выравнивания файловых секций

Возможно, владельцы Visual C++ 5.0 заметили, что у них в результате получаются EXE-файлы куда меньшего размера, чем сказано здесь. Дело в том, что компоновщик версии 5.0 использовал выравнивание секций исполняемого файла на величину 512 байт. Начиная же с версии 6.0, при сборке приложения используется другая величина выравнивания – 4К. Это позволяет быстрее загружать такой файл в Windows 98 и более новых версиях ОС.

Вернуть прежнюю величину выравнивания можно, задав недокументированную опцию компоновщика /opt:nowin98:

cl /MD test.cpp user32.lib /link /opt:nowin98

Размер EXE в результате составляет менее 3-х килобайт! Но не забудьте, что такой файл будет медленнее загружаться в память, и что он по-прежнему требует наличия MSVCRT.DLL.

Радикальные меры: отказываемся от CRT Startup

Если ампутация кажется вам разумной хирургической операцией, то стартовый код CRT можно выбросить из программы совсем.

Что это означает? Отказавшись от некоторых привычных удобств, которые предоставляет CRT, можно писать на C/C++, не используя возможностей, которые требуют поддержки со стороны CRT.

В мире Windows API такое решение не пугает многих. Взгляните, например, на NullSoft Installer

В самом деле, для файловых операций можно использовать функции Win API, вместо динамической памяти C++ использовать кучу (хип) Windows, для форматирования можно использовать wsprintf вместо sprintf, для сравнения строк – lstrcmp вместо strcmp и т.д.

При этом важно понимать, что CRT – это обычная библиотека, функции которой вполне можно вызывать из такой программы (как и из программы на ассемблере). Главное – это отказаться от функций, которые влекут за собой включение раздутого кода инициализации (или, в крайнем случае, включить его необходимую часть самостоятельно).

Мэтт Питрек, давний ведущий колонки "Under The Hood" в Microsoft Systems Journal (ныне – MSDN Magazine), посвятил этому вопросу цикл статей в MSJ под общей тематикой "Code Liposuction" ("обезжиривание кода"). Интересующиеся могут найти их в архиве Periodicals MSDN.

Более свежая информация содержится в его статье "Reduce EXE and DLL Size with LIBCTINY.LIB" в январском выпуске MSDN Magazine

за 2001 год. Предлагаемая автором версия "крохотной" библиотеки исполнения выполняет минимальную инициализацию (например, вызывает конструкторы глобальных объектов) и даже предоставляет собственные версии таких функций, как printf и malloc. При этом размер выполняемого модуля оказывается зачастую меньше 3 Кб.

Но не будем забираться так далеко – ведь в нашем коде нет никаких конструкторов, правда?

В данном случае можно просто указать, что функция main будет точкой входа в программу (вместо функции инициализации):

cl test.cpp user32.lib /link /entry:main /opt:nowin98 /subsystem:console

В результате также получим исполняемый файл размером менее 3 Кб (я вновь использовал опцию /opt:nowin98). Разница теперь лишь в том, что он не требует внешней CRT-библиотеки (библиотека user32.lib необходима для функции MessageBox, но она является частью ядра Windows).

Версия ATL: макрос _ATL_MIN_CRT

Пригодность этого подхода доказывается тем, что с его помощью создано множество легких COM-компонентов. Но непонимание принципов его работы может легко завести в тупик, как видно из цитаты в начале статьи.

В составе библиотеки ATL версии 3 и более ранних имеется файл atlimpl.cpp. Он, как правило, включается в один из исходных файлов проекта (чаще всего в stdafx.cpp) с помощью директивы #include. В atlimpl.cpp находится "облегченная" реализация стартового кода CRT: в нее входят только вариант функции xxxCRTStartup, упомянутой ранее, и "обертки" для работы с динамической памятью – функции malloc, calloc, realloc, free и операторы new/delete. Они непосредственно вызывают функции Windows для работы с кучей – HeapAlloc и HeapFree. Как ни странно, этого достаточно, чтобы заставить заработать без CRT startup множество программ.

Собственно, сама эта реализация доступна, только если определен символ препроцессора _ATL_MIN_CRT. Таким образом, есть возможность легко управлять включением или исключением стартового кода CRT.

ПРИМЕЧАНИЕ

Важный момент при использовании макроса ATL_MIN_CRT: по-прежнему нельзя включать объявления глобальных переменных, классы которых имеют конструкторы или деструкторы, так как код, их вызывающий, содержится только в CRT.

Эта проблема решена в библиотеке ATL 7.0 (не удивляйтесь, как и многие другие приложения Microsoft, ATL перескочила с версии 3 на версию 7), поставляемой с компилятором MS VC++ 7.0. Тем же, кто пользуется прежними версиями компилятора, могу посоветовать воспользоваться отличной библиотекой Andrew Nosenko's ATL/AUX Library, в которой содержится код вызова конструкторов/деструкторов. Для этого необходимо включать в проект вместо atlimpl.cpp файл AuxCrt.cpp из комплекта библиотеки.

Кто виноват?

Теперь ясно, что причиной появления ошибки "unresolved external symbol _main" стало включение стартового кода CRT. То есть, была явно или неявно использована какая-либо функция, которая содержит ссылку на структуру данных, находящуюся в модуле с кодом инициализации. При включении компоновщиком в программу этого модуля возникает следующая внешняя ссылка: в теле mainCRTStartup есть вызов main. Вот и все, мы получили наше "любимое" сообщение об ошибке.

Поделиться:
Популярные книги

Измена. Тайный наследник

Лаврова Алиса
1. Тайный наследник
Фантастика:
фэнтези
5.00
рейтинг книги
Измена. Тайный наследник

Инквизитор Тьмы

Шмаков Алексей Семенович
1. Инквизитор Тьмы
Фантастика:
попаданцы
альтернативная история
аниме
5.00
рейтинг книги
Инквизитор Тьмы

Наследник

Майерс Александр
3. Династия
Фантастика:
попаданцы
аниме
фэнтези
5.00
рейтинг книги
Наследник

Ротмистр Гордеев 3

Дашко Дмитрий
3. Ротмистр Гордеев
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Ротмистр Гордеев 3

(Не)нужная жена дракона

Углицкая Алина
5. Хроники Драконьей империи
Любовные романы:
любовно-фантастические романы
6.89
рейтинг книги
(Не)нужная жена дракона

Идеальный мир для Лекаря 28

Сапфир Олег
28. Лекарь
Фантастика:
юмористическое фэнтези
аниме
фэнтези
5.00
рейтинг книги
Идеальный мир для Лекаря 28

Сыночек в награду. Подари мне любовь

Лесневская Вероника
1. Суровые отцы
Любовные романы:
современные любовные романы
5.00
рейтинг книги
Сыночек в награду. Подари мне любовь

Инквизитор Тьмы 2

Шмаков Алексей Семенович
2. Инквизитор Тьмы
Фантастика:
попаданцы
альтернативная история
аниме
5.00
рейтинг книги
Инквизитор Тьмы 2

Генерал Скала и ученица

Суббота Светлана
2. Генерал Скала и Лидия
Любовные романы:
любовно-фантастические романы
6.30
рейтинг книги
Генерал Скала и ученица

Искатель 1

Шиленко Сергей
1. Валинор
Фантастика:
фэнтези
попаданцы
рпг
5.00
рейтинг книги
Искатель 1

Сердце Дракона. Том 10

Клеванский Кирилл Сергеевич
10. Сердце дракона
Фантастика:
фэнтези
героическая фантастика
боевая фантастика
7.14
рейтинг книги
Сердце Дракона. Том 10

Печать мастера

Лисина Александра
6. Гибрид
Фантастика:
попаданцы
технофэнтези
аниме
фэнтези
6.00
рейтинг книги
Печать мастера

Выстрел на Большой Морской

Свечин Николай
4. Сыщик Его Величества
Детективы:
исторические детективы
полицейские детективы
8.64
рейтинг книги
Выстрел на Большой Морской

Кодекс Крови. Книга VII

Борзых М.
7. РОС: Кодекс Крови
Фантастика:
боевая фантастика
попаданцы
аниме
5.00
рейтинг книги
Кодекс Крови. Книга VII