Я узнал от своего коллеги, что можно написать и выполнить программу на C, не написав main()
функции. Сделать это можно так:
my_main.c
/* Compile this with gcc -nostartfiles */
#include <stdlib.h>
void _start() {
int ret = my_main();
exit(ret);
}
int my_main() {
puts("This is a program without a main() function!");
return 0;
}
Скомпилируйте его с помощью этой команды:
gcc -o my_main my_main.c –nostartfiles
Запустите его с помощью этой команды:
./my_main
Когда нужно делать такие вещи? Есть ли какой-нибудь сценарий в реальном мире, где это было бы полезно?
_start()
и другие вещи за пределамиmain()
._start
какой точке входа, кромеmain
(за исключением того, что имя точки входа определяется реализацией для автономных (встроенных) реализаций).Ответы:
Символ
_start
- это точка входа в вашу программу. То есть адрес этого символа - это адрес, на который происходит переход при запуске программы. Обычно функция с именем_start
предоставляется файлом с именем,crt0.o
который содержит код запуска для среды выполнения C. Он настраивает некоторые параметры, заполняет массив аргументовargv
, подсчитывает количество аргументов и затем вызываетmain
. Послеmain
возвращенияexit
называется.Если программа не хочет использовать среду выполнения C, она должна предоставить свой собственный код для
_start
. Например, эталонная реализация языка программирования Go делает это потому, что им нужна нестандартная потоковая модель, которая требует некоторой магии со стеком. Также полезно предоставить свои собственные,_start
когда вы хотите написать действительно крошечные программы или программы, которые делают нетрадиционные вещи.источник
_start
происходит из объектного файлаcrt0.o
._start
; на самом деле, он вообще не указывает, что происходит передmain
вызовом, он просто указывает, какие условия должны выполняться приmain
вызове. Это больше условность для точки входа,_start
которая восходит к старым временам.Хотя
main
это точка входа для вашей программы с точки зрения программистов,_start
это обычная точка входа с точки зрения ОС (первая инструкция, которая выполняется после того, как ваша программа была запущена из ОС)В типичной программе C и особенно C ++ много работы было сделано до того, как выполнение перейдет в main.
Особенно такие вещи, как инициализация глобальных переменных.Здесь вы можете найти хорошее объяснение всего, что происходит между_start()
иmain()
после того, как main снова завершил работу (см. Комментарий ниже).Необходимый для этого код обычно предоставляется авторами компилятора в файле запуска, но с помощью флага
–nostartfiles
вы, по сути, говорите компилятору: «Не беспокойтесь, давая мне стандартный файл запуска, дайте мне полный контроль над тем, что происходит прямо из Начало".Иногда это необходимо и часто используется во встроенных системах. Например, если у вас нет ОС, и вам нужно вручную включить определенные части вашей системы памяти (например, кеши) перед инициализацией ваших глобальных объектов.
источник
_start()
(или фактически другой функцией, вызываемой им), и во многих программах Bare-Metal вы явно копируете все глобальные данные из флэш-памяти в ОЗУ. во-первых, что также происходит в_start()
, но этот вопрос не касался ни C ++, ни кода с нуля._start
, библиотека C не будет инициализирована, если вы не предпримете специальные шаги, чтобы сделать это самостоятельно - вполне может быть небезопасно использовать какую-либо не асинхронную сигнальную функцию из такой программы. (Нет официальной гарантии, что какая-либо библиотечная функция будет работать, но функции, безопасные для асинхронных сигналов, вообще не могут ссылаться на какие-либо глобальные данные, поэтому им придется изо всех силmalloc
не инициализированы.errno
(например ,read
иwrite
являюсь асинхронным сигналом безопасными и могу установитьerrno
) , и что , вероятно , может быть проблемой , в зависимости от того, когда именно за нитьerrno
места выделяется ,Вот хороший обзор того, что происходит во время запуска программы раньше
main
. В частности, это показывает, что__start
это фактическая точка входа в вашу программу с точки зрения ОС.Это самый первый адрес, с которого указатель команд начнет отсчет в вашей программе.
Код там вызывает некоторые подпрограммы библиотеки времени выполнения C, чтобы выполнить некоторую уборку, затем вызывает ваш
main
, а затем отключает и вызываетexit
любойmain
возвращенный код выхода .Одна картинка стоит тысячи слов:
PS: этот ответ перенесен из другого вопроса, который SO услужливо закрыл как дубликат этого.
источник
Когда вам нужен собственный код запуска для вашей программы.
main
это не первая запись для программы C,_start
это первая запись за кулисами.Пример в Linux:
Если вы имеете в виду, реализуйте наши собственные
_start
:Да, в большинстве коммерческих встроенных программ, с которыми я работал, нам необходимо реализовать собственное
_start
в соответствии с нашими конкретными требованиями к памяти и производительности.Если вы имеете в виду, отбросьте
main
функцию и измените ее на что-нибудь другое:Нет, я не вижу в этом никакой пользы.
источник