是C程序所需的main()吗?

时间:2010-11-06 15:29:07

标签: c language-lawyer

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

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

7 个答案:

答案 0 :(得分:63)

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

对于像嵌入式系统(或操作系统本身)这样的独立环境,它的实现已定义。来自C99 5.1.2

  

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

     

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

关于Linux本身的启动方式,Linux内核的起点是start_kernel,但为了更全面地了解整个启动过程,您应该启动here

答案 1 :(得分:9)

main()函数由libc附带的目标文件调用。由于内核没有链接到libc,因此它有自己的入口点,用汇编语言编写。

答案 2 :(得分:9)

嗯,不,但是......

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程序”,只是一个带有用C语言编写的对象模块的“Linux程序”。

答案 3 :(得分:3)

Paxdiablo的answer涵盖了两个不会遇到主要情况的情况。让我补充几点:

  • 许多其他程序的插件系统(例如浏览器或文本编辑器等)没有main()
  • 用C编写的Windows程序没有main()。 (他们改为使用WinMain()。)

答案 4 :(得分:0)

操作系统加载程序必须调用单个入口点;在GNU编译器中,入口点在crt0.o链接目标文件中定义,其源代码是汇编程序文件crt0.s - 在执行各种运行时启动任务(如建立)后调用main()堆栈,静态初始化)。因此,在构建链接缺省crt0.o的可执行文件时,必须有一个main(),否则会出现链接器错误,因为在crt0.o中main()是一个未解析的符号。

修改crt0.s以调用不同的入口点是可能的(如果有些不正确和不必要)。只需确保您创建特定于项目的对象文件而不是修改默认版本,否则您将破坏该计算机上的每个构建。

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

答案 5 :(得分:0)

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

答案 6 :(得分:-2)

在机器语言中,事物按顺序执行,首先执行先执行的操作。因此,默认情况下编译器会调用main方法以符合C标准。

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

但是你可以编写调用你的任意C程序函数的汇编代码(实际上调用库函数的方式也是这样),这与其他可执行文件的工作方式相同。但问题是你不能用简单的标准C来做,你必须求助于汇编甚至其他一些编译器特定的技巧。

这是一个一般性和肤浅的解释,我在目的上避免​​了一些技术差异,因为它们似乎并不相关。