C语言程序运行时的一些细节
本章可以看作是 《Unix 环境高级编程》Ch7 的笔记。
C 程序运行的开始和结束
一个可以运行的 C 语言总要有一个 main 函数,main 函数现在的完整定义是 int main(int argc, char *argv[] )
,现在的 C 语言已经不允许写成 void main()
的形式了,main 函数必须有返回值,如果 main 函数没有返回值,那么编译器会在最后默认加上 return 0
的语句。
C 语言从 main 函数开始运行是一个约定俗成的东西,甚至影响了后面的好多语言也是从类似名为 main 函数的入口开始运行程序。但是当内核执行 C 语言程序的时候,并不是直接调用了 main 函数,而是先通过一个特殊的启动程序 (a special start-up routine),这个特殊的启动程序将作为程序的起始地址开始运行,启动程序会从内核中获取命令行参数和环境变量值,然后去调用 main 函数。
一个进程的正常终止是有五种方式:
- 从 main 函数返回
- 调用 exit 函数。
- 调用 _exit 函数或者 _Exit 函数。
- 最后一个线程从其启动例程返回。
- 从最后一个线程调用 pthread_exit 。
所以,这个启动的例程实际上调用的是 exit(main(argc, argv[]))
这个函数。
退出程序有三种分别是
- exit()
- _exit()
- _Exit()
C 语言结束的时候,也是调用的 exit 函数,exit 函数在执行的时候,会先执行一些清理处理,并且关闭所有可能的 IO 流,对所有在缓冲的数据进行冲洗。
如果直接调用 _exit 或者 _Exit 函数,则会直接退出,进入内核。
这三个函数都有一个调用参数,称为终止状态,如果调用这些函数不带这个终止状态,或者 main 函数执行了一个没有返回值的 return 语句(这个时候相当于调用的 exit 函数没有参数),或者 main 函数没有声明返回值为整数类型,那么这个进程终止的状态就是未定义的。否则,进程的终止状态就是 0 。
一个完整的 C 语言的启动过程如图。
我们之前说过,exit 函数退出的时候,还需要进行收尾工作,那么如果我们想自定义这个收尾工作的话,可以调用 atexit () 函数,它会登记我们想要调用的收尾工作调用的函数,然后让 exit 自动进行调用。这些收尾函数可以称为 handler 。
atexit 函数原型如下,它的参数是一个函数地址,exit 调用这些函数的顺序与登记这些函数的顺序相反,可以理解为存在一个handler 函数栈,越后登记的函数越先被调用。
int atexit( void (*func) (void));
C 程序的存储空间布局
一个典型的C语言程序结构如图。
C 程序一般由几个部分组成,
- 正文段/程序段 (text) ,就是记录了程序的二进制代码。通常是只读的,防止出现意外指令被改写。
- 初始化数据段 (Data) 存储已经初始化的全局变量或者静态变量。
- 未初始化数据段(BSS)保存了未初始化的静态变量,在程序家在的时候会将此段中的数据初始化为 0 。
- 栈 保存局部变量,函数调用栈信息,程序开始时自动分配内存,结束后自动释放内存。递归函数调用的时候,会形成一个新的栈帧,函数调用不会互相影响。
- 堆 在堆中进行动态的内存分配,需要手动分配和释放内存。
C语言程序运行时的一些细节的更多相关文章
- Swift和OC,是编译型语言、解释性语言、运行时语言
首先需要明确的一点是,什么是编译型语言和解释性语言 编译型语言,就是在其执行过程中需要先将其经过编译成机器码来给计算机识别的,其执行效率就会比较高这个是显而易见的,常见比如:C.C++ 而解释型语言, ...
- java程序运行时内存分配详解
java程序运行时内存分配详解 这篇文章主要介绍了java程序运行时内存分配详解 ,需要的朋友可以参考下 一. 基本概念 每运行一个java程序会产生一个java进程,每个java进程可能包含一个 ...
- Java程序运行时内存划分
1.Java程序跨平台运行的原因 主要原因是:各种平台的JVM和字节码文件 Java源程序--具体平台的机器代码文件---被编译器翻译成平台无关的Class文件,又用特定JVM运行字节码文件,JVM在 ...
- 小程序运行时如何助力传统APP转型?
小程序和H5或者RN有什么区别?优越性在哪里? 长期以来,移动互联网界一直在寻找一种既能获得Native原生的体验,又可以低门槛快速开发的技术.在这个过程中出现了很多尝试,例如React Native ...
- c/c++编译时,指定程序运行时查找的动态链接库路径
http://blog.csdn.net/tsxw24/article/details/10220735 c/c++编译时,指定程序运行时查找的动态链接库路径 分类: c/c++ linux 2013 ...
- C# 获取程序运行时路径
Ø 前言 开发中,很多时候都需要获取程序运行时路径,比如:反射.文件操作等..NET Framework 已经封装了这些功能,可以很方便的使用. C# 中有很多类都可以获取程序运行时路径,我们没必要 ...
- java程序运行时内存分配详解 (转)
转自:http://www.tuicool.com/articles/uU77v2 一. 基本概念 每运行一个java程序会产生一个java进程,每个java进程可能包含一个或者多个线程,每一个Ja ...
- linux下实现在程序运行时的函数替换(热补丁)
声明:以下的代码成果,是参考了网上的injso技术,在本文的最后会给出地址,同时非常感谢injso技术原作者的分享. 但是injso文章中的代码存在一些问题,所以后面出现的代码是经过作者修改和检测的. ...
- 【Visual Studio】控制台程序运行时一闪而过
问题:写一个C#控制台程序,运行时控制台一闪而过.程序结束.无法看清控制台输出的结果. 办法: 方法一二三都有人写过百度经验了:怎么解决VS运行程序一闪而过 其实还有一种办法,就是把控制台程序改为Wi ...
随机推荐
- Oracle procedure 在命令行里面执行出错
One procedure do well in SQL developer but error during exceute it under sqlplus command line: Remem ...
- HTML+Jquery实现多图片上传预览功能
HTML:使用input的onchange事件,它一改变就触发事件 <p id="p3"> <input name="File" onchan ...
- Python一秒搭建ftp服务器,帮助你在局域网共享文件
"老板 来碗面" "要啥面?" "内牛满面.." 最近项目上的事情弄得人心累,本来是帮着兄弟项目写套入口代码,搞着搞着就被拉着入坑了.搞开发 ...
- java抽象类,接口(接口定义,实现接口,instanceof运算符,对象转换)
抽象类 在面向对象的概念中,所有的对象都是通过类来表述的,但并不是所有的类都能够完整的描绘对象,如果一个类中没有包含足够的信息来描绘一类具体的对象,这样的类就是抽象类.抽象类往往用来表征对问题领域进行 ...
- 尺取法two pointers
目的:对给定的一个序列,在序列中寻找包含全部需求的.长度最小的一段子序列.一般用来解决具有单调性的区间问题. 时间复杂度:O(n) https://blog.csdn.net/lxt_lucia/ar ...
- io流函数略解(java_input流)[二]
背景 在写这篇随笔之前,已经写了io流函数略解(java_File)(一),主要是总结了File的一些操作,以及一些源码介绍. 在Io实际应用中,实际上运用在如果会操作File,实际上很难写出一点能实 ...
- unix环境高级编程中的err_quit,err_sys用到的知识点
unix环境高级编程中的err_quit,err_sys 环境 os CentOS release 6.7 (Final) gcc 4.4.7 c语言预备知识 标准输入输出文件 在linux系统中一切 ...
- Appium之UIAutomator API选择元素
UI Automator测试框架提供了一组API来构建UI测试. 利用UI Automator API可以执行在测试设备中,打开‘设置’菜单或应用启动器等操作. UI Automator测试框架非常适 ...
- 笔记||Python3之字典
字典的定义与特性: 字典的每个键值key ==> value 对用冒号:分割,每个键值对之间用逗号分割,整个字典包括在花括号{}中. 字典名 = {键名1:值1, 键名2:值2} 如:dict ...
- 【CuteJavaScript】ES2019 新特性汇总
最近 ECMAScript2019,最新提案完成:tc39 Finished Proposals,我这里也是按照官方介绍的顺序进行整理,如有疑问,可以查看官方介绍啦~ 另外之前也整理了 <ES6 ...