Подтвердить что ты не робот

Является ли main() обязательным для программы C?

Хорошо название говорит все. Является ли функция main() абсолютно необходимой для программы C?

Я спрашиваю об этом, потому что я смотрел на код ядра Linux, и я не видел функцию main().

4b9b3361

Ответ 1

Нет, стандарт ISO C указывает, что функция main требуется только для размещенной среды (например, с базовой ОС).

Для автономной среды, такой как встроенная система (или сама операционная система), она определена. От C99 5.1.2:

Определены две среды исполнения: автономные и размещенные. В обоих случаях запуск программы происходит, когда назначенная функция C вызывается средой выполнения.

В автономной среде (в которой выполнение программы C может происходить без какой-либо выгоды от операционной системы), имя и тип функции, вызываемой при запуске программы, определяются по реализации.

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

Ответ 2

Функция main() вызывается объектным файлом, включенным в libc. Поскольку ядро ​​не связывается с libc, оно имеет свою собственную точку входа, написанную на ассемблере.

Ответ 3

Ну, нет, но...

C99 указывает, что main() вызывается в размещенной среде "при запуске программы", однако вам не нужно использовать поддержку времени выполнения C. Ваша операционная система выполняет файлы изображений и запускает программу по адресу, предоставленному компоновщиком.

Если вы хотите написать свою программу для соответствия требованиям операционной системы, а не C99, вы можете сделать это без main(). Тем не менее, чем более современная (и сложная) система, тем больше проблем у вас будет с библиотекой C, делающей предположения о том, что используется стандартный запуск.

Вот пример для Linux...

$ cat > nomain.S
.text
_start:
    call    iamnotmain
    movl    $0xfc, %eax
    xorl    %ebx, %ebx
    int     $0x80
.globl _start
$ cat > demo.c

void iamnotmain(void) {
    static char s[] = "hello, world\n";
    write(1, s, sizeof s);
}
$ as -o nomain.o nomain.S
$ cc -c demo.c
$ ld -static nomain.o demo.o -lc
$ ./a.out
hello, world

Возможно, это не "программа C99", а просто "программа Linux" с объектным модулем, написанным на C.

Ответ 4

Paxdiablo answer охватывает два случая, когда вы не столкнетесь с основным. Позвольте мне добавить еще пару:

  • Многие плагины для других программ (например, браузеры или текстовые редакторы и т.д.) не имеют main().
  • Программы Windows, написанные на C, не имеют main(). (Вместо этого они имеют WinMain().)

Ответ 5

Загрузчик операционных систем должен вызывать одну точку входа; в компиляторе GNU точка входа определяется в файле связанных объектов crt0.o, источником для этого является файл ассемблера crt0.s - который вызывает main() после выполнения различных задач запуска во время выполнения (таких как установление стек, статическая инициализация). Поэтому при создании исполняемого файла, который связывает значение по умолчанию crt0.o, вы должны иметь main(), иначе вы получите ошибку компоновщика, поскольку в crt0.o main() является неразрешенным символом.

Было бы возможно (если несколько извращенным и ненужным) изменить crt0.s для вызова другой точки входа. Просто убедитесь, что вы создаете такой объектный файл, специфичный для вашего проекта, а не изменяете версию по умолчанию, иначе вы будете разбивать каждую сборку на этой машине.

Сама ОС имеет свой собственный запуск C (который будет вызываться из загрузчика), поэтому он может вызывать любую точку входа, которую он хочет. Я не смотрел на источник Linux, но представлю, что у него есть собственный crt0.s, который будет вызывать все, что есть в C entry entry point.

Ответ 6

main вызывается glibc, который является частью приложения (кольцо 3), а не ядром (кольцо 0).
драйвер имеет другую точку входа, например, база драйверов Windows на WDM начинается с DRIVERENTRY

Ответ 7

В машинный язык вещи выполняются последовательно, сначала выполняется первое. Таким образом, по умолчанию используется компилятор для вызова основного метода, соответствующего стандарту C.

Ваша программа работает как библиотека, представляющая собой набор скомпилированных функций. Основное различие между библиотекой и стандартным исполняемым файлом заключается в том, что для второго компилятор генерирует код сборки, который вызывает одну из функций в вашей программе.

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

Это было предназначено как общее и поверхностное объяснение, есть некоторые технические различия, которых я избегал нарочно, поскольку они не кажутся релевантными.