一、 学习过程

编写程序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编译成功还需要哪些文件?

四、 学习感想

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

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

  1. [转载]C#控制台应用程序里调用自己写的函数的方法

    (2011-08-15 15:52:13) 转载▼ 标签: 转载 分类: 技术类 原文地址:C#控制台应用程序里调用自己写的函数的方法作者:萧儿 最近写程序,遇到了一个很白痴的问题,记录下来,免得下次 ...

  2. Python 为什么没有 main 函数?为什么我不推荐写 main 函数?

    毫无疑问 Python 中没有所谓的 main 入口函数,但是网上经常看到一些文章提"Python 的 main 函数"."建议写 main 函数"-- 有些人 ...

  3. WPF启动流程-自己手写Main函数

    WPF一般默认提供一个MainWindow窗体,并在App.Xaml中使用StartupUri标记启动该窗体.以下通过手写实现WPF的启动. 首先先介绍一下VS默认提供的App.Xaml的结构,如下图 ...

  4. 【C解毒】怎样写main()函数

    [C解毒]怎样写main()函数(出处: CUNIX论坛)

  5. [置顶] Embedded Server:像写main函数一样写Web Server

    1.传统的JEE Web Server 传统的JEE中,如果我们想要部署一个Web Application,我们需要首先安装一个Container Server,如JBoss,WebLogic,Tom ...

  6. C++程序设计基础(8)main函数

    注:读<程序员面试笔记>笔记总结 1.知识点 (2)main函数的形式 //first type int main() //second type int main(int argc,ch ...

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

    问题引入: 一般WPF创建之后可以直接运行并不需要编写Main函数指定入口,但是在开发的过程中会遇到一些情况需要自定义Main让WPF从指定的Main函数中进行启动,这样可能会更好控制一点.但是我们再 ...

  8. C 语言main 函数终极探秘(&& 的含义是:如果 && 前面的程序正常退出,则继续执行 && 后面的程序,否则不执行)

           所有的C程序必须定义一个称之为main的外部函数,这个函数是程序的入口,也就是当程序启动时所执行的第一个函数,当这个函数返回时,程序也将终止,并且这个函数的返回值被看成是程序成功或失败的 ...

  9. python 如何写好main函数

    每个程序员在学习编程的过程中,肯定没少写过main()函数,Python程序员也不例外.本文为大家分享Python之父Guido van Rossum推荐的函数写法,可以大大提高这个函数的灵活性. 一 ...

随机推荐

  1. Number Sequence - HDU 1711(KMP模板题)

    题意:给你一个a串和一个b串,问b串是否是a串的子串,如果是返回b在a中最早出现的位置,否则输出-1   分析:应该是最简单的模板题了吧..... 代码如下: ==================== ...

  2. war文件

    原文地址:http://blog.sina.com.cn/s/blog_4cbc6fdd0100fojv.html jar包和war包的区别:war是一个web模块,其中需要包括WEB-INF,是可以 ...

  3. angular 按需加载

     angular.module('app',[]) .controller('ctrl',function ($http,$scope){ //ctrl控制器,名称作用的范围 html中ng-cont ...

  4. UVA 140 (13.07.29)

     Bandwidth  Given a graph (V,E) where V is a set of nodes and E is a set of arcsin VxV, and anorderi ...

  5. Android 使用 RemoteViews 发送自定义通知 ,遇到 Couldn't expand RemoteViews问题总结

    在RemoteViews这种调用方式中,你只能使用以下几种界面组件: Layout:     FrameLayout, LinearLayout, RelativeLayout Component: ...

  6. Android BroadcastReceiver实例Demo(有序广播的发送)

    上一篇简介了广播的发送,这篇主要介绍下,有序广播的发送. 设置完相关属性的时候,广播就会依照有序的方式进行发送: 发送顺序: 先发送第二条广播: 再发送第一条广播: 最后发送第三条广播. 代码例如以下 ...

  7. 跨域请求,关于后端session会话丢失的解决办法

    目前使用前后端分离的模式开发,后端提供跨域接口.前端jsonp调用,绑定数据,但是在该站点下有个人中心模块存在的情况下,服务端的session会话会被跨域请求覆盖改掉 大家都知道tomcat使用coo ...

  8. 【iOS解决思路】得到某个view所在的ViewController

    在一个tableViewCell中有个btn,如何得到它所在的viewcontroller,以便于push出新的viewController? 我的思路是传值,但网上有下面这种方法,分享. 跟得到某个 ...

  9. 使用solr报错,错误信息 include(SolrClient.php): failed to open stream: No such file or directory

    这个是因为本地没有安装php-solr的扩展导致的,安装方法(使用的是ubuntu) cd /optwget http://pecl.php.net/get/solr-1.0.2.tgztar -xv ...

  10. IIS 7.5 配置伪静态

    IIS 7.5 配置伪静态_win服务器_脚本之家 win7下IIS的安装和配置 图文教程详细出处参考:http://www.jb51.net/article/29787.htm http://blo ...