为什么c程序里一定要写main函数

一、 学习过程

编写程序f.c:

对其进行编译,正常通过,再对其进行连接,出现错误:

显示的出错信息为:

翻译成中文是:在c0s模块没有定义符号’_main’。

那么这个错误信息可能与文件c0s.obj有关。那么是什么原因导致编译出错呢?

既然已经将程序编译成了obj文件,那么用之前我们经常使用的link.exe能否将它连接呢?结果是可以的:

用debug查看f.exe:

程序是从06fb:0到06fb:001c,一共29个字节。但是整个程序的代码有541字节:

执行最后一条ret指令,返回到b800处:

查看该地址的上一条指令:

发现上一条指令是push ds,不是跳转指令,所f.exe没有正确返回.

由上图知f函数的偏移地址是0.

编写程序m.c:

对m.c进行编译连接,这一次连接没有出现错误。

用debug查看m.exe,发现代码还是在1fa处:

程序是从06fb:01fa到06fb:0216,一共29个字节。但是整个程序的代码有4.19KB:

程序返回06fb:011d,查看该地址之前的代码:

发现上一条指令是call 01fa,即跳转到主程序所在代码段,所以程序的返回是正确的。

观察两个程序的汇编代码发现:

(1)f.exe的偏移地址为0,在debug中直接用u命令就可看到,而m.exe的偏移地址为1fa,在debug中用u命令查看到的不是main函数中的代码。

(2)f.exe有没有被调用,所以函数返回是错误的,m.exe被调用了,所以函数的返回是正确的。

由上图知:对main函数进行调用的指令地址为06fb:011a,整个m.exe程序返回的指令是:

我们发现,对main函数进行调用的指令和程序返回的指令都不是我们所写的语句,而是编译或连接过程中提供的。

没有main函数时,Tc里出现连接错误,提示c0s.obj里的main是没有定义的,而没有c0s.exe就无法对程序进行连接,那么有可能tc是把c0s.obj或者它的一部分与m.exe

一起进行连接生成exe文件。而且对main函数进行调用的指令和程序返回的指令应该就是c0s.obj所提供的。那么我们要对c0s.obj进行研究,可以用link.exe对它进行连接,再用debug查看汇编代码。发现虽然link提示错误,但是还是生成了c0s.exe文件:

用debug查看c0s.exe和m.exe发现连个程序的代码非常相似,那么m.exe中调用了main函数,c0s.exe中调用了什么呢?

可以看到,c0s.exe中本来应该指向main函数段的地方因为找不到main函数,所以指向了下一条语句。还有这两段程序中call的程序段地址都不一样。

所以C语言编程一定要写main函数是因为c0s.obj连接后要调用main函数执行其功能,如果我们把main函数写成其他的函数,c0s.obj里的代码不会识别。如f.exe虽然可以由link.exe连接,但是不会被调用,而是直接执行其中的内容,造成返回错误。而书上说c0s.obj的作用是:在程序开始运行,进行相关初始化,再调用main函数,返回后进行相关的资源释放,环境恢复等工作,再将程序返回。那么如果我们改写c0s.obj使其调用的不是main函数而是其他函数,编程时就可以不写main函数了。

编写c0s.txt:

用masm编译成obj文件,覆盖原来的c0s.obj文件。

将f.c重新编译连接,这次的连接成功了。

用debug查看f.exe:

发现我们重写的c0s.obj的内容出现在程序中,f函数的偏移地址为0012,且返回正确。f.exe可以正确运行。

编写新的程序f.c:

这里的实现原理与上一篇的最后一个程序相同,不同的是将main函数换成了f函数,因为我们重写了c0s.obj,所以同样可以执行。但是为什么前者是用malloc函数开辟了20个字节的空间,而后者是直接赋0呢?我觉得应为是200:0的安全空间,所以可以直接使用,但是如果在比较复杂的程序中或者空间比较紧张,则要先开辟空间,这样比较安全。

二、 解决的问题

(1) c0s.obj文件的作用:在程序开始运行,进行相关初始化,再调用main函数,返回后进行相关的资源释放,环境恢复等工作,再将程序返回。

(2) 可否用其他函数代替main函数?

答:可以,但是要修改c0s.obj文件。

三、 未解决的问题

(1) link.exe是集成了c0s.obj、emu.obj等所有编译需要的文件吗?

(2) 如果不修改c0s.obj,要将f.c编译成功还需要哪些文件?

四、 学习感想

我们在解决复杂的问题时,要把它分解成一个一个小问题来解决。这次的研究是书上提出了问题来帮助我们理解和思考,但是真正解决问题时是没有人来帮助我们划分问题、提出问题的。所以在平时的学习中,我们要多督促自己养成好的思考的习惯。

时间: 2024-10-14 02:21:58

为什么c程序里一定要写main函数的相关文章

WPF应用程序启动的问题(自定义Main函数启动)

问题引入: 一般WPF创建之后可以直接运行并不需要编写Main函数指定入口,但是在开发的过程中会遇到一些情况需要自定义Main让WPF从指定的Main函数中进行启动,这样可能会更好控制一点.但是我们再APP.xaml.cs中自定义Main函数后运行时会提示程序已经存在Main,即出现以下错误: 错误 CS0111 类型"App"已定义了一个名为"Main"的具有相同参数类型的成员  错误 Type 'App' already defines a member cal

python 如何写好main函数

每个程序员在学习编程的过程中,肯定没少写过main()函数,Python程序员也不例外.本文为大家分享Python之父Guido van Rossum推荐的函数写法,可以大大提高这个函数的灵活性.一般来说,Python程序员可能是这样写main()函数的:"""Module docstring.This serves as a long usage message."""import sysimport getoptdef main(): par

iOS程序main函数之前发生了什么

我是前言 一个iOS app的main()函数位于main.m中,这是我们熟知的程序入口.但对objc了解更多之后发现,程序在进入我们的main函数前已经执行了很多代码,比如熟知的+ load方法等.本文将跟随程序执行顺序,刨根问底,从dyld到runtime,看看main函数之前都发生了什么. 从dyld开始 动态链接库 iOS中用到的所有系统framework都是动态链接的,类比成插头和插排,静态链接的代码在编译后的静态链接过程就将插头和插排一个个插好,运行时直接执行二进制文件:而动态链接需

【转载】MFC的Main函数跑哪去了

原文:http://blog.csdn.net/weiwenhp/article/details/8455471 习惯的思维 用习惯了C的人要看一个程序时首先会想到找到那个main函数在哪,然后再顺着往下看.因为main函数作为程序的入口点,整个程序都是从那开始执行的.当在C++中SDK(win32 API project)开发时也继承沿用C的思维,是有个main函数,不过现在的main函数改名字了,叫WinMain,当然有时还有变体,比如叫_tWinMain,反正名字中总会带个Main,让我们

java之main函数

1.标准的main函数形式 对于main函数,只要是 public static void main(String[] args) public static void main(String... args) public static void main(String args[]) 这样的,虚拟机都能找到并进入程序,如果你的main函数没有这样写,会提示找不到main函数. 2.main函数的修饰 (1)public,因为需要从外部调用; (2)static,这时main所在的类还没有实例

c#中main函数为什么要static

假设没有static关键字,那意味着需要用生成一个实例后才可以调用这个main方法,而main方法是程序入口点,你没有进入main方法,自然无法生成一个实例,既然没有实例,那就无法调用main函数,岂不矛盾?所以main函数被设置为static. Main()函数在C#里非常特殊,它是编译器规定的所有可执行程序的入口点.由于其特殊性,对Main()函数我们有以下几条准则: Main()函数必须封装在类或结构里来提供可执行程序的入口点.C#采用了完全的面向对象的编程方式,C#中不可以有像C++那样

main函数的标准形式

本文转载自http://blog.chinaunix.net/uid-26495963-id-3054731.html C的设计原则是把函数作为程序的构成模块.main()函数称之为主函数,一个C程序总是从main()函数开始执行的.一.main()函数的形式    在最新的 C99 标准中,只有以下两种定义方式是正确的:        int main( void )--无参数形式        {         ...        return 0;        }          

C语言main()函数详解

C的设计原则是把函数作为程序的构成模块.main()函数称之为主函数,一个C程序总是从main()函数开始执行的. 一.main()函数的形式 在最新的 C99 标准中,只有以下两种定义方式是正确的: int main( void )  /* 无参数形式 */{    ...    return 0;}int main( int argc, char *argv[] ) /* 带参数形式 */{    ...    return 0;}int指明了main()函数的返回类型,函数名后面的圆括号一

第33课 main函数与命令行参数

1. main函数的概念 (1)C语言中main函数称之为主函数 (2)一个程序是从main函数开始执行的 [编程实验]main函数的原型究竟是什么 //以下四个main函数都是合法的 //第1种 //main() //{ //} //第2种 //void main() //{ //} //第3种:——标准的入口函数 int main() { return 0; } //第3种:——标准的入口函数 //int main() //{ // //没写返回值 //} [思考]为什么编译器支持那么多种不