Це поки що лише чернетка
Розглянемо наступний простий приклад консольного додатку Windows в якому друкуються всі параметри, що передаються через командний рядок, і змінні оточення (envp - це покажчик на масив, що містить змінні оточення з їхніми значеннями, розділені знаком рівності (=)):
.bat файл, що компілює цей приклад, має вигляд:
При цьому передбачається наступне розташування файлів
У всіх Windows-додатках має бути вхідні функція. за реалізацію якої відповідаєте ви. Існує дві такі функції:
_tWinMain і _tmain це насправді макроси, які розкриваються як WinMain або wWinMain для _tWinMain і main або wmain для _tmain в залежності від того використовується Unicode чи ні.
Насправді вхідні функція операційною системою не викликається. Замість цього відбувається звернення до стартової функції з бібліотеки C / C ++. заданої під час компонування параметром -entry: командного рядка. Вона инициализирует бібліотеку С / С ++, щоб можна було викликати такі функції, як malloc і free. а також забезпечує коректне створення будь-яких оголошених вами глобальних і статичних С ++ - об'єктів до того, як починається виконання вашого коду. У наступній таблиці показано, в яких випадках реалізуються ті чи інші вхідні функції.
Типи додатків і відповідні їм вхідні функції
Компоновщик відповідає за вибір відповідної стартовою функції з бібліотеки С / С ++ при компонуванні виконуваного файлу. Якщо заданий ключ / SUBSYSTEM: WINDOWS. компоновщик шукає в коді функцію WinMain або wWinMain. Якщо цих функцій немає, компонувальник повідомляє про помилку "unresolved external symbol". В іншому випадку компоновщик вибирає WinMainCRTStartup або wWinMainCRTStartup, відповідно.
Аналогічним чином, якщо заданий ключ / SUBSYSTEM: CONSOLE. компоновщик шукає в коді функцію main або wmain і вибирає відповідно mainCRTStartup або wmainCRTStartup; якщо в коді немає ні main, ні wmain, повідомляється про ту ж помилку - "unresolved external symbol".
Але мало хто знає, що в проекті можна взагалі не вказувати ключ / SUBSYSTEM компоновщика. Якщо ви так і зробите, компонувальник буде сам визначати підсистему для вашого застосування. При компонуванні він перевірить, яка з чотирьох функцій (WinMain, wWinMain, main або wmain) присутній у вашому коді, і на підставі цього Оберіть підсистему і стартову функцію з бібліотеки С / С ++.
Тепер кілька зауважень по .bat файлу і ключам компілятора і компоновщика
При створенні .bat файлу потрібно чітко стежити за тим, щоб створюваний текстовий файл мав формат завершення рядка в стилі Windows або Unix. але не Mac. інакше bat файл просто не буде запускатися.
Для нормальної роботи компілятора перед викликом cl.exe або link.exe необхідно викликати call "% vc_path% vcvarsall.bat" x86. Цей bat файл инициализирует змінні оточення INCLUDE. LIB. LIBPATH. PATH і деякі інші необхідні для роботи cl.exe і link.exe. Наприклад, в моєму випадку було
При виклику cl.exe використовувалися наступні ключі:
- / С - компіляція без зв'язування
- / ZI - компілятор включає зневадження в базу даних програми (тільки для x86)
- / Nologo - пригнічує відображення інформації про компіляторі
- / W3 - встановлює рівень попереджень компілятора на 3 рівень
- / Od - відключає оптимізацію (так як / Od запобігає переміщенню коду, установка цього ключа полегшує процес налагодження)
- / Oy - запобігає створення покажчиків фрейма в стеці виклику, / Oy- відключає така поведінка (тільки для x86)
- / D "_DEBUG" - визначається при компіляції з ключами / LDd, / MDd і / MTd
- / D "_WINDOWS" - визначає, що цільова OS - Windows
- / D "UNICODE" - вказує компілятору на необхідність використовувати в додатку версії Win API функцій для роботи з Unicode
Наприклад, ось фрагмент з WinUser.h. Тобто, якщо ми при компіляції вказуємо / D "UNICODE" і в своєму коді викликаємо CreateWindowEx. то насправді відбувається звернення до CreateWindowExW - / D "_UNICODE" - подібно UNICODE вказує на використання в додатку версій функцій з бібліотеки С для роботи з Unicode рядками. Так, наприклад, в заголовки TChar.h можна знайти визначення наступного макросу: Тепер при виклику _tcslen і певному _UNICODE виклик дозволяється в wcslen. в іншому випадку - в strlen. За замовчуванням в нових С ++ - проектах Visual Studio визначено _UNICODE (як і UNICODE)
- / Gm - включає мінімальну перекомпіляцію, яка дозволяє перекомпілювати тільки файли з зміненим вихідним кодом
- / EHsc - перехоплюються тільки С ++ виключення і гарантується, що зовнішні З функції, ніколи не викинуть С ++ виняток
/ RTC (Run-Time Error Checks) (Перевірка помилок часу виконання)
/ RTC1 - еквівалентно / RTCsu
/ RTCs - включає перевірку стекового фрейма часу виконання, що означає:
- ініціалізацію локальних змінних ненульовими значеннями. Це дозволяє ідентифікувати баги, які не виявляються в отладочной збірці. Більшої ймовірність, що змінна в стеці залишатиметься нульовою в отладочной збірці ніж в рілізной збірці, так як компілятор оптимізує стек змінних в рілін збірці. Будучи одного разу використаної пам'ять відведена під стік не обнуляється компілятором. З цього, подальшому не початкові змінні в стеку міститимуть значення залишився від попереднього використання цієї області пам'яті.
- Перевірка виходу за межі локальних змінних, таких як масиви. / RTCs не визначає вихід за межі при зверненні до пам'яті явилася результатом вирівнювання компілятором положення структури в пам'яті. Таке може статися при використанні вирівнювання (С ++). / Zp або pack або, якщо ви распологайся елементи структури в такому порядку, який змушує компілятор вставляти відступи.
- Перевірка покажчика стека, що дозволяє визначити руйнування покажчика стека. Руйнування покажчика стека може статися при невідповідності тип дзвінка. Наприклад, використовуючи покажчик на функцію, ви можите викликати функцію з DLL, яка експортується як __stdcall. але ви визначили покажчик на функцію як __cdecl.
зауваження:
стековий фрейм (функції) - область пам'яті, що виділяється щоразу, коли викликається функція, призначається для тимчасового зберігання аргументів і локальних змінних функції.
/ RTCu - змушує компілятор видавати попередження, коли змінна використовується без ініціалізації. Наприклад, команда, яка генерує попередження (4-го рівня) С4701 може також генерувати помилку часу виконання при встановленому ключі / RTCu. Будь-які команди, які генерують попередження компілятора (рівня 1 і 4) С4700. будуть також генерувати помилку часу виконання при встановленому ключі / RTCu.
Проте, розглянемо наступний фрагмент коду: