Преамбула
Программы на C и C++, как правило, проводят бо́льшую часть своей жизни внутри функции
main()
и функций, прямо или косвенно вызываемых из
main()
. Тем не менее, на самом деле выполнение программы начинается вовсе не с
main()
, а с некоторого кода из стандартной библиотеки, поставляемой вместе с компилятором. Таковой код, по идее, должен подготавливать окружение для других функций стандартной библиотеки, которые, возможно, позовёт
main()
, а также параметры самой
main()
(под Windows; Unix-системы имеют тенденцию передавать
argc/argv/envp
в подготовленном виде прямо при запуске процесса, но речь не о них). Симметрично, завершающий
return
в функции
main()
— вовсе не последняя инструкция программы, после него следует ещё немного кода из стандартной библиотеки.
В Visual Studio «настоящая» точка входа в программу называется
mainCRTStartup
. В комплекте с VS идут исходники стандартной библиотеки, в VS2015 определение
mainCRTStartup
находится в
%PROGRAMFILES(X86)%\VC\crt\src\vcruntime\exe_main.cpp
, но, впрочем, всю работу выполняет
exe_common.inl
рядом. Давайте туда посмотрим.
...
// If this module has any thread-local destructors, register the
// callback function with the Unified CRT to run on exit.
_tls_callback_type const * const tls_dtor_callback = __scrt_get_dyn_tls_dtor_callback();
if (*tls_dtor_callback != nullptr && __scrt_is_nonwritable_in_current_image(tls_dtor_callback))
{
_register_thread_local_exe_atexit_callback(*tls_dtor_callback);
}
__telemetry_main_invoke_trigger(nullptr);
//
// Initialization is complete; invoke main...
//
int const main_result = invoke_main();
//
// main has returned; exit somehow...
//
__telemetry_main_return_trigger(nullptr);
if (!__scrt_is_managed_app())
exit(main_result);
if (!has_cctor)
_cexit();
// Finally, we terminate the CRT:
__scrt_uninitialize_crt(true, false);
return main_result;
...