Страница 3 из 15
Точка входа в программу Функция [w]main или [w]WinMain, с которой начинается выполнение программы, вовсе не является точкой входа исполняемого модуля! На самом деле, программа на C++ начинает работу с выполнения специальной процедуры инициализации. Что касается Win32, то адрес этой процедуры и содержится в поле AddressOfEntryPoint заголовка Portable Executable (PE) выполняемого файла. Она представляет собой обычную функцию C, описанную с соглашением о вызовах __stdcall. В зависимости от настроек проекта, в Visual C++ эта функция может называться [w]mainCRTStartup, [w]WinMainCRTStartup или _DllMainCRTStartup (символ 'w' добавляется к имени для Unicode-проектов). Конкретно же для сборки приложения имя функции-точки входа можно задать опцией линкера /entry. Умолчанием для Visual C++ является "mainCRTStartup". Все сказанное справедливо и для некоторых других компиляторов C++ для Win32. Что же происходит во время ее выполнения? Вот типичный сценарий работы такой функции (случай DLL здесь не рассматривается). - Инициализируются переменные CRT (такие, как errno и osver). Многопоточная библиотека требует особой инициализации.
- Происходит инициализация динамической памяти (кучи).
- Инициализируется среда обработки ошибок в вычислениях с плавающей точкой. Это необходимо не только для библиотечных функций (таких, как sqrt), но и для преобразований между целочисленными и плавающими типами данных.
- Получаются значения аргументов командной строки программы и переменных среды.
- В случае необходимости, происходит инициализация консоли и привязка стандартного вывода к файловым дескрипторам C. При старте исполняемого файла, у которого в уже упомянутом заголовке PE значение поля Subsystem равно 3 (Windows character-mode executable), создается консоль. Это значение можно задать опцией линкера /subsystem. Выбор подсистемы выполнения также влияет на выбор стартовой функции (если ее имя не задано явно). Умолчанием является "console".
- Происходит вызов цепочки функций инициализации CRT и конструкторов глобальных переменных (подробнее об этом - в следующем разделе).
- И лишь после этого вызывается функция [w]main или [w]WinMain. Коротко можно сказать, что функция xxxCRTStartup вызывает соответствующую функцию xxx.
- Программа работает.
- Выполняется последовательность действий по очистке, к которой мы еще вернемся.
- И, наконец, происходит завершение процесса.
Теперь, наконец, можно ответить на мой вопрос: он был задан некорректно :). В самом деле, результат сборки будет зависеть от набора опций компоновщика, установленных в проекте или по умолчанию. Так, например, при вызове компилятора в командной строке таким образом: мы получим консольную программу и сообщение "Hello from main()" (вспомните, что говорилось об умолчаниях). А вызвав компилятор вот так:
cl test.cpp user32.lib /link /entry:WinMainCRTStartup /subsystem:console
| мы получим "чудо чудное": программу, у которой выполняется функция WinMain, но создается окно консоли. |