C语言 程序的编译系统解析

目录
  • 程序的翻译环境和执行环境
  • 编译和链接
    • 翻译环境
    • 编译的几个阶段
      • 预处理
      • 编译
      • 汇编
    • 链接
    • 运行环境

今天我来补一下C语言篇的程序的编译的一篇文章,也算是有一个结尾了。

程序的翻译环境和执行环境

在ANSI C的任何一种实现中,存在两个不同的环境 :

第1种是翻译环境,在这个环境中源代码被转换为可执行的机器指令。

第2种是执行环境 ,它用于实际执行代码。

一个.c的文件事如何变成.exe的可执行文件的呢?下面这张图片是一个大概的过程:

编译和链接

翻译环境

  • 组成一个程序的每个源文件通过编译过程分别转换成目标代码( object code )。
  • 每个目标文件由链接器( linker )捆绑在一 起,形成一个单一-而完整的可执行程序。
  • 链接器同时也会引入标准C函数库中任何被该程序所用到的函数,而且它可以搜索程序员个人的程序库,将其需要的函数也链接到程序中。

编译的几个阶段

接下来,我来用Linux平台来给大家演示一下编译的三个过程:

我们先编写一个简单C程序:

然后执行这样一句指令:

gcc test.c

这句指令是让gcc这个编译器来编译我们的代码,执行完这句指令我们会发现会生成一个a.out这样一个可执行文件,

我们执行再下面这样一句指令:

./a.out

这样我们就可以执行这个可执行文件了,

为了让大家更好地感受到编译的过程,我们来一步一步看:

预处理

我们执行再下面这样一句指令,让代码预处理完之后就停下来:

gcc -E test.c -o test.i

这句指令的意思就是把预处理完之后的信息输出到一个test.i的文件中。

可以发现的是,这里多了一个test,i的文件,我们可以打开看一看:

可以发现的是,有三个点发生了变化:

  • 头文件被展开
  • 宏被文本替换了
  • 注释被删除了

我们对原代码做一个处理,不包含stdio.h的头文件,我们自己写一个头文件:

再来看一下,预处理后的文件是什么样子的:

效果通上面一样。

所以预处理的几个动作

  • 头文件的包含
  • 预处理指令的完成(eg:#define、#pragma…)
  • 注释的删除

编译

执行再下面这样一句指令让文件进行编译形成汇编代码:

gcc -S test.c

执行完之后就可以生产出一个test.s的文件,我们可以打开看一看:

这里其实就是汇编代码。

所以编译的几个动作

  • 语法分析
  • 词法分析
  • 语义分析
  • 符号汇总

符号汇总: 符号汇总的都是全局的符号。例如上面我们的代码头文件就汇总了一个Add,.c文件就汇总的一个Add和main。

汇编

接下来我们执行这样一条指令:

gcc -c test.c

对源文件进行汇编,结果生成了一个test.o的目标文件:

打开这个文件,我们会发现这是一个我们看不懂的二进制文件:

所以其实汇编是把汇编代码转换为二进制代码(机器指令)。

这个过程还做了一件件事——形成符号表

链接

链接做的两个事情

  • 合并段表
  • 符号表的合并和符号表的重定位

在Linux系统下,test.o二进制文件是用一个elf这样的格式来组织文件的。

elf会把文件组织成一个段。test.o和Add.o都有一个段,那么我们怎样才能看懂elf格式的文件呢?

我们有这样一个工具叫做readelf,他可以看懂这样一个文件,所以我们输入这样一条指令:

readelf test.o -a

我们就确实可以看到这样一个段的存在。

然后这下面还有符号表的汇总:

其实a.out这个文件也是elf格式的,所以其实链接就是把这几个elf格式的文件的段表合并,然后test中的Add函数就有了地址。

运行环境

程序执行的过程:

  • 程序必须载入内存中。在有操作系统的环境中:一般这个由操作系统完成。在独立的环境中,程序的载入必须由手工安排,也可能是通过可执行代码置入只读内存来完成。
  • 程序的执行便开始。接着便调用main函数。
  • 开始执行程序代码。这个时候程序将使用一个运行时堆栈(stack),存储函数的局部变量和返回地址。程序同时也可以使用静态(static)内存,存储于静态内存中的变量在程序的整个执行过程一直保留他们的值。
  • 终止程序。正常终止main函数;也有可能是意外终止。

到此这篇关于C语言 程序的编译系统解析的文章就介绍到这了,更多相关C语言 程序编译内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • C语言程序的编译与预处理详解

    目录 一.程序的编译 1. 编译阶段 2.链接 二.预处理详解 1.预定义符号 2.#define定义的标识符 3.#define定义的宏 4.#unef 总结 一.程序的编译 我们写的源文件(*.c)是经过怎样的处理生产可执行文件(*.exe)的呢?这种处理有两个步骤-编译和链接.源文件在编译阶段通过编译器将每个源文件转换为目标文件(这些文件是可执行的机器指令),再通过链接器将其捆绑到一起,生成一个完整的可执行程序. 1. 编译阶段 编译阶段可细分为3个阶段:预处理(即预编译).编译.汇编 预

  • 如何将C语言代码转换为应用程序(也就是编译)

    C语言是高级语言,它的语法接近于人类的自然语言,但比自然语言严谨.计算机无法直接将C语言的代码运行,他们并不懂得什么是C语言,实际上,计算机只处理他们的机器语言,所以我们必须为自己找一个翻译,这个翻译可分为2种: 1.编译器 编译器是"文章的译者",它在我们完成创作后将其翻译(实际上是编译)成为机器语言. 2.解释器 解释器是"随声翻译",代码运行的同时它们就开始工作,BASIC就是使用解释器,一般认为这种方法效率很低. C语言要请第1种翻译,要想让C语言代码执行,

  • 简单分析针对ARM平台的C语言程序的编译问题

    我们知道在C语言编译时,有那么几个常用的优化编译选项,分别是-O0,-O1,-O2,-O3以及-Os.之前一直觉得既然是优化选项,顶多是优化一下逻辑,提高一些效率或者减少一下程序大小而已.很少会觉得它们会影响程序的最终结果.直到最近在ARM平台上发现一个程序里的一个bug,才觉得这些优化选项有时候也没那么智能.或者说针对ARM平台,还没有那么智能.       首先看这么一段程序,此程序是我将问题简单化的程序: #include<stdio.h> #include<string.h>

  • C语言 程序的编译系统解析

    目录 程序的翻译环境和执行环境 编译和链接 翻译环境 编译的几个阶段 预处理 编译 汇编 链接 运行环境 今天我来补一下C语言篇的程序的编译的一篇文章,也算是有一个结尾了. 程序的翻译环境和执行环境 在ANSI C的任何一种实现中,存在两个不同的环境 : 第1种是翻译环境,在这个环境中源代码被转换为可执行的机器指令. 第2种是执行环境 ,它用于实际执行代码. 一个.c的文件事如何变成.exe的可执行文件的呢?下面这张图片是一个大概的过程: 编译和链接 翻译环境 组成一个程序的每个源文件通过编译过

  • C 语言程序结构示例解析

    C 程序结构 在我们学习 C 语言的基本构建块之前,让我们先来看看一个最小的 C 程序结构,在接下来的章节中可以以此作为参考. C Hello World 实例 C 程序主要包括以下部分: 预处理器指令 函数 变量 语句 & 表达式 注释 让我们看一段简单的代码,可以输出单词 "Hello World": #include <stdio.h> int main() { /* 我的第一个 C 程序 */ printf("Hello, World! \n&qu

  • 详解C语言函数返回值解析

    详解C语言函数返回值解析 程序一: int main() { int *p; int i; int*fun(void); p=fun(); for(i=0;i<3;i++) { printf("%d\n",*p); p++; } return 0; }; int* fun(void) { static int str[]={1,2,3,4,5}; int*q=str; return q; } //不能正确返回 虽然str是在动态变量区,而该动态变量是局部的,函数结束时不保留的.

  • 易语言程序破解浅析

    易语言程序用PEID查壳显示的是 Visual C++ 6.0[overlay]   ,其中包含有ecode区段,这基本就是易语言程序是不会错了,应为易语言底层也是用的C++的编译系统所以也是Visual C++ 6.0, overlay(附加数据)是什么意思呢?这是易语言独有的特性:程序在库中运行,就像加了可一样所以说它带有附加数据. 如果你拿到一个易语言的程序载入 OD后就直接查找字符串之类的是无果的,就像前面所说的,易语言程序就像被加了壳一样,所以你必须在壳把程序完全解压释放出来你才能查看

  • Java语言资源国际化步骤解析

    这篇文章主要介绍了Java语言资源国际化步骤解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 语言资源国际化步骤: 1. 定义资源文件(如:language),需要使用命令native2ascii命令进行转码:(native2ascii是jdk中的转码工具,在jdk的bin目录下) 2. 定义工具类(LangusgeUtils)读取资源文件: 3. 定义调用资源文件类(TestResourceBundle) 注意:native2ascii 命

  • 手把手带你走进Go语言之语法基础解析

    目录 概述 Go 语法基础 关键字 标识符 数据类型 变量声明 多变量声明 值类型和引用类型 概述 Golang 是一个跨平台的新生编程语言. 今天小白就带大家一起携手走进 Golang 的世界. (第 2 课) Go 语法基础 Go 程序可以由多个标记组成: 关键字 标识符 常量 字符串 符号 关键字 Go 语言有 25 个关键字: 关键字 作用 var & const 变量和常量的声明 package & import 导入 func 用于定义函数和方法 return 用于函数返回 d

  • c#语言程序构建基块

    目录 1.成员 2.辅助功能 3.字段 4.方法 4.1参数 4.2方法主体和局部变量 4.3静态和实例方法 4.4虚方法.重写方法和抽象方法 4.5方法重载 5.其他函数成员 5.1构造函数 5.2"属性" 5.3索引器 5.4事件 5.5运算符 5.6终结器 6.表达式 7.语句 上文c#语言入门类型和成员中介绍的类型是使用以下构建基块生成的:成员*_.表达式和语句_*. 1.成员 class 的成员要么是静态成员,要么是实例成员. 静态成员属于类,而实例成员则属于对象(类实例).

  • Go语言程序开发gRPC服务

    目录 前言 介绍 入门 proto server client 流方式 proto server client 验证器 proto Token 认证 认证函数: 拦截器: 初始化: 实现接口: 连接: 单向证书认证 生成证书 gRPC 代码 双向证书认证 生成带 SAN 的证书 gRPC 代码 Python 客户端 总结 前言 gRPC 这项技术真是太棒了,接口约束严格,性能还高,在 k8s 和很多微服务框架中都有应用. 作为一名程序员,学就对了. 之前用 Python 写过一些 gRPC 服务

  • Go语言程序查看和诊断工具详解

    想必Java 的开发者没有不知道或者没用过 jps 这个命令的,这个命令是用来在主机上查看有哪些 Java 程序在运行的. 我刚用 Go 语言程序的时候也很苦恼,我部署在公司服务器上的 Go 程序,其他的同事由于不清楚就经常找不到. 那么 Go 语言有没有像 jps 这样的工具呢?当然有,不仅有,而且还是 Google 自己出品的,官方认证(这种问题 Google 不可能自己想不到啊).名称也跟 jps 很像,叫 gops. 安装 gops 并不包含在官方安装包中,不属于标准工具.需要手动获取.

  • 编写C语言程序进行进制转换的问题实例

    题目 题目描述:      将M进制的数X转换为N进制的数输出.      输入:      输入的第一行包括两个整数:M和N(2<=M,N<=36).      下面的一行输入一个数X,X是M进制的数,现在要求你将M进制的数X转换成N进制的数输出.      输出:      输出X的N进制表示的数.      样例输入:      16 10      F      样例输出:      15      提示:      输入时字母部分为大写,输出时为小写,并且有大数据. 思路 大整数乘法

随机推荐