成功心法(8):如果提高自身的技术修养(2)

  凡是学过C语言的人都知道main()函数,但未必一定清楚其鲜为人知的“私隐”,下面将为此揭开其神秘的面纱。

对于标准的C语言来说,main 是所有 C 程序中都必须包含的一个函数名字。main()是C 程序中第一个要执行的函数,必须通过main()中的函数调用才能执行其它函数。只有当main()执行结束时,整个程序才会执行结束。尽管在逻辑上main()是程序中第一个要执行的函数,但在程序行文上,它不一定是第一个函数。

main()函数是由程序员自行编写的,但其函数说明符是由语言规定好的。它可以定义成无参函数,详见程序清单1。

程序清单 无参数函数

int main(void)

{

......

}

也可以带有2个特定参数 argc与argy,详见程序清单2。

程序清单2 int main(int argc,char argy[])函数

int main(int argc,char argy[])

{

......

}

argc与argy 特定参数名字是由语言预定义的标识符,尽管有些C编译器也允许使用其它的一些参数,但标准C只支持argc与argy。在C语言中,编译器处理main()函数与其它函数的方式基本上是一样的,其区别主要表现在运行时,编译器可以支持argc与argy这2个特殊的参数。

由于计算机仅认识机器码,而不认识C语言中的main()函数,因此必须有一段程序来识别C编译器编译的main()函数并调用它。其实在C语言的标准中,有一个非常重要的概念,那就是环境。

环境是指程序翻译与执行所在的计算背景(或称计算上下文),环境可以分为翻译环境与执行环境2类。对于C程序员来说,一般不必关心翻译环境。而在C语言的标准中,对执行环境的解释大致如下:

执行环境是指程序经过翻译后执行的环境,执行环境与翻译环境可以是同一环境,也可以是不同环境。ANSIC规定了2种执行环境,即独立式执行环境与非独立式执行环境。两者的主要区别在于,独立式执行环境不需要操作系统支持,它实际上是一种裸机执行环境,如洗衣机控制器的微控制器实际上就是这样一种执行环境,而非独立式执行环境则需要操作系统的支持,而用于程序设计的执行环境绝大多数都是非独立式执行环境。ANSIC只规定了独立式执行环境的最小规则,因为这种环境可能千差万别。但ANSIC却仔细地规定了在非独立式环境下程序执行的具体规则,包括程序启动、程序执行与程序终止的规则。

对于执行环境的规则,不开发编译器是不需要详细了解的。但从使用者的角度来看,可以这样理解:执行环境是一个软件(及其所运行的硬件)的集合,这个软件提供了基本的库函数和调用main()函数的方式。对于非独立执行环境来说,C语言程序通常编译成对应操作系统的应用程序(一个文件)。假如C语言程序已经编译成应用程序abc.exe,如果在命令行中输入“abc.exe [参数字符串]”后,那么操作系统将执行以下步骤:

  • 找到abc.exe文件并进行分析;
  • 根据分析的结果将指令和数据加载到内存的指定位置;
  • 将参数字符串存储到特定位置(可能是预处理过的);
  • 根据操作系统的不同,执行一些特定的初始化;
  • 初始化堆栈指针;
  • 将所有的寄存器设置为预定义的值;
  • 执行应用程序的第一条指令。

一般来说,应用程序的第一条指令并不是main()函数的第一条指令。编译器会提供实现参数转换等功能的接口代码,并最终调用main()函数。main()函数也会返回到接口代码,此时接口代码将main()函数的返回值处理为操作系统需要的方式,并按照操作系统给定的方式将结果和控制权提交给操作系统。

对于独立执行环境来说,系统往往是裸机,没有任何软件支持,更不可能访问文件了。其步骤如下:

  • 编译器会一般将C语言程序编译为符合某种格式的目标文件;
  • 通过某种烧录或下载工具将目标文件以系统能识别的方式存储到系统的特定位置;
  • 复位系统,系统执行复位向量指定的第一条指令。

一般来说,系统复位后硬件仅进行了有限的初始化,并不能直接运行main(),还需要一个所谓的“启动代码”,将系统引导到C语言的main()函数。启动代码可能全部由编译器提供,也有可能部分需要用户提供。启动代码的内容大致如下:

  • 初始化堆栈指针;
  • 初始化总线控制器、中断控制器、MMU等必须初始化的硬件;
  • 初始化C运行时库;
  • 可能为main()函数提供参数;
  • 调用main()函数。

对于独立执行环境来说,main()函数是一般不返回的。尽管一些编译器也提供返回处理,但都是为停机、软件复位或调用用户提供的函数。

其实main()函数与其它函数最大的区别在于main()是根函数。在一个标准的C语言程序(仅调用标准的库函数和自己编写的函数)中,所有的其它函数都由main()函数直接或间接调用。如果将函数调用关系画成一个图(一般为树形结构),那么一个标准的C语言程序只有一颗函数调用树,其树根就是main()。

需要注意的是程序只有执行后才会调用别的函数,所以“根函数”是动态执行的概念。

当然,还牵涉到词法分析、语义分析等,在此不再阐述。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值