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 ...
随机推荐
- OC中内存管理(转)
OC内存管理 一.基本原理 (一)为什么要进行内存管理. 由于移动设备的内存极其有限,所以每个APP所占的内存也是有限制的,当app所占用的内存较多时,系统就会发出内存警告,这时需要回收一些不需要再继 ...
- Spring Securtiy 认证流程(源码分析)
当用 Spring Security 框架进行认证时,你可能会遇到这样的问题: 你输入的用户名或密码不管是空还是错误,它的错误信息都是 Bad credentials. 那么如果你想根据不同的情况给出 ...
- 如何不用BPM配置时间
详细方案 配置时间 您需要同步消息接口(JDBC)和异步消息接口(对JEDBCReceiver的响应).对于SAP BAPI,我们不需要消息接口. 注意:CIMS是数据库系统 消息接口(请求/响应) ...
- 转:OAuth2 深入介绍
OAuth2 深入介绍 1. 前言 2. OAuth2 角色 2.1 资源所有者(Resource Owner) 2.2 资源/授权服务器(Resource/Authorization Server) ...
- 单片机内存分配中的.text .data .bss heap stack
[本文转自:http://www.51hei.com/bbs/dpj-41696-1.html] .text段:代码段(code segment/text segment)通常是指用来存放程序执行代码 ...
- “copy” 与 “=“赋值
前拷贝 与 赋值 >>> a = {1:'one',2:'two',3:'three'}>>> b = a.copy()>>> c = a&g ...
- CF 1130A 1130B 1130C1129A1 1129A2 1129B(Round542A B C D1 D2 E)题解
A : Be Positive 题目地址:https://codeforces.com/problemset/problem/1130/A 题解:让你求是否满足一个d使得数列长为n的a数组的每个数除以 ...
- UVA-156
Most crossword puzzle fans are used to anagrams - groups of words with the same letters in different ...
- 通过ansible自动化部署zabbix应用
zabbix在实际的应用中,可能需要监控的主机非常多,而每个主机的操作系统类型.版本也都不尽相同,在这种环境下,通过手动安装zabbix的agent端已经不现实了,此时就需要借助自动化工具完成zabb ...
- 聊聊技术选型 - Angular2 vs Vue2
作者介绍:李旸,美团点评前端工程师,3 年 Web 前端开发经验,现在是美团点评点餐团队的一员. "Come, and take choice of all my library, And ...