是一个C程序所需的主要()?

那么标题说明了一切。 对于C程序来说, main()函数是绝对必要的吗?

我问这是因为我在看Linux内核代码,而我没有看到main()函数。

不,ISO C标准规定只有托pipe环境(例如具有底层操作系统的环境)才需要mainfunction。

对于像embedded式系统(或操作系统本身)这样的独立环境,它是实现定义的。 从C99 5.1.2

定义了两个执行环境:独立式和托pipe式。 在这两种情况下,当执行环境调用指定的C函数时都会发生程序启动。

在一个独立的环境中(C程序的执行可能没有任何操作系统的好处),程序启动时调用的函数的名称和types是实现定义的。

至于Linux本身是如何启动的,Linux内核的起点是start_kernel,但是为了更全面地了解整个启动过程,你应该从这里开始。

main()函数由libc包含的对象文件调用。 由于内核不与libc链接,因此它有自己的入口点,用汇编语言编写。

那么不,但是…

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编写的。

Paxdiablo的答案涵盖了两个你不会遇到主要的情况。 让我再添加几个:

  • 其他程序的许多插件系统(如浏览器或文本编辑器等)没有main()
  • 用C编写的Windows程序没有main() 。 (他们有一个WinMain()来代替。)

操作系统加载器必须调用一个入口点; 在GNU编译器中,入口点是在crt0.o链接的目标文件中定义的,源代码是汇编文件crt0.s – 在执行各种运行时启动任务(如build立一个堆栈,静态初始化)。 所以当构build链接默认crt0.o的可执行文件时,你必须有一个main(),否则你会得到一个链接器错误,因为在crt0.o中main()是一个未解决的符号。

这将是可能的(如果有点不正确和不必要的)修改crt0.s来调用一个不同的入口点。 只要确保你制作了一个特定于你的项目的对象文件,而不是修改默认的版本,否则你将破坏该机器上的每一个版本。

操作系统本身有自己的C运行时启动(这将从引导程序调用),因此可以调用任何它希望的入口点。 我没有看过Linux源代码,但想象它有它自己的crt0.s,它将调用任何C代码入口点。

主要由glibc调用,这是应用程序(环3)的一部分,而不是内核(环0)。
驱动程序有另一个入口点,例如基于WDM的Windows驱动程序是从DRIVERENTRY开始的

在机器语言中,事情是顺序执行的,先执行的是先执行。 所以,默认情况下编译器会调用你的main方法来适应C标准。

你的程序就像一个库,它是编译函数的集合。 一个库和一个标准可执行文件的主要区别在于,第二个编译器生成汇编代码,调用程序中的一个函数。

但是你可以编写调用你的任意C程序函数的汇编代码(实际上调用库函数的方法也是如此),而且这与其他可执行文件的工作方式相同。 但事情是你不能用纯C标准来做,你不得不求助于程序集甚至其他一些编译器的特定技巧。

这是作为一个普遍而肤浅的解释,我有意避免了一些技术上的差异,因为它们似乎并不相关。