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 ...
随机推荐
- python实现一可升降式的冒泡排序
前几天看了个冒泡的排序,这里手敲了一下代码,简单记录如下: def bubble_sort(arr, order='asc'): # #可选升降序的冒泡排序, order>0升序,order&l ...
- 5、Docker 核心原理-资源隔离和限制
Docker 资源隔离 Docker 是利用linux的LXC技术,内核的Kernel namespace Namespace: PID - 通过PID的namespace隔离,可以嵌套 NET - ...
- Oracle procedure 在命令行里面执行出错
One procedure do well in SQL developer but error during exceute it under sqlplus command line: Remem ...
- MATLAB工具包——curvelet变换的理解(转)
curvelet下载的curvelet工具包,有以下三个文件:fdct_usfft_matlab.fdct_wrapping_matlab.mecv三个文件夹添加到matlab路径中即可. curve ...
- 《Windows内核安全与驱动开发》 3.1 字符串操作
<Windows内核安全与驱动开发>阅读笔记 -- 索引目录 <Windows内核安全与驱动开发> 3.1 字符串操作 一.字符串的初始化 1. 判断下列代码为什么会蓝屏? U ...
- 用墨卡托和GPS坐标计算距离时误差测试
iOS墨卡托和GPS坐标计算距离时误差测试,测试结果: 墨卡托和gps坐标来回转换没有误差. 墨卡托坐标计算出的距离比gps坐标计算出的距离大,100/92*100 = 108米,每100米多算出8米 ...
- 输入URL到页面渲染
输入网址回车或者刷新页面到页面传染出来的整个流程 DNS 解析 HTTP三次握手 -> TCP/IP连接 浏览器发送请求 服务器返回请求的文件 (html) 浏览器渲染 1. DNS 解析 查找 ...
- matplotlib画图总结--常用功能
0.内容范围 多曲线图.图例.坐标轴.注释文字等. 1.曲线图 多曲线图.图例.网格.坐标轴名称.图标名.坐标轴范围等. from matplotlib import pyplot as plt im ...
- HotStuff共识协议详解
1. 前言 HotStuff提出了一个三阶段投票的BFT类共识协议,该协议实现了safety.liveness.responsiveness特性.通过在投票过程中引入门限签名实现了O(n)的消息验证复 ...
- 使用Cocoapods创建私有podspec
Cocoapods是非常好用的一个iOS依赖管理工具,使用它可以方便的管理和更新项目中所使用到的第三方库,以及将自己的项目中的公共组件交由它去管理.Cocoapods的介绍及优点本文就不在赘述,我开始 ...