c语言篇——程序的编译(代码片段)

呆呆兽学编程 呆呆兽学编程     2023-02-16     172

关键词:

今天我来补一下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的头文件,我们自己写一个头文件:

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

效果通上面一样。

所以预处理的几个动作

  1. 头文件的包含

  2. 预处理指令的完成(eg:#define、#pragma…)

  3. 注释的删除

编译

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

gcc -S test.c

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

这里其实就是汇编代码。

所以编译的几个动作

  1. 语法分析

  2. 词法分析

  3. 语义分析

  4. 符号汇总

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

汇编

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

gcc -c test.c

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

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

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

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

链接

链接做的两个事情

  1. 合并段表
  2. 符号表的合并和符号表的重定位

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

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

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

readelf test.o -a

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

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

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

运行环境

程序执行的过程:

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

c编译篇|什么是源文件可执行程序编译与链接?(代码片段)

...代码的文件就叫做源文件(SourceFile)。每种编程语言的源文件都有特定的后缀 查看详情

计算机基础篇之二(代码片段)

目录  1.1编程语言    1)低级语言    2)高级语言  1.2内核kernel  1.3程序  1.4进程  1.5cpu内存空间1.1编程语言1)低级语言#离机器越近语言#二进制机器指令#汇编语言#ADD,R0,R1,ST...2)高级语言#离近人类越近的... 查看详情

let‘sgogo语言入门篇(代码片段)

吉祥物镇楼go语言简述Go(Golang)是谷歌开发的一种静态强类型、编译型、并发型,并具有垃圾回收功能的编程语言。Go专门针对多处理器系统应用程序的编程进行了优化,它是一种非常有用强大的系统语言,go... 查看详情

菜鸟攻略–c语言多文件编程初探:使用gcc手动编译多文件c程序(代码片段)

菜鸟攻略–C语言多文件编程初探(二):使用gcc手动编译多文件C程序四年前我发布了一篇菜鸟攻略–C语言多文件编程初探(一),没想到这篇文章成了我博客上阅读量最多,评论数也最多的文章。当... 查看详情

菜鸟攻略–c语言多文件编程初探:使用gcc手动编译多文件c程序(代码片段)

菜鸟攻略–C语言多文件编程初探(二):使用gcc手动编译多文件C程序四年前我发布了一篇菜鸟攻略–C语言多文件编程初探(一),没想到这篇文章成了我博客上阅读量最多,评论数也最多的文章。当... 查看详情

c语言----程序编译(预处理)(代码片段)

...宏的替换去除注释2)编译gcctest.i-S生成test.s的文件把C语言代码转化为汇编代码编译部分深入学习编译原理语法分析词法分析语义分析符号汇总1).把c程序所有的全局符号汇总(add.c中的全局符号是Ad 查看详情

c语言进阶学习笔记七程序执行+调试技巧(实用技巧篇)(代码片段)

文章目录一、程序执行篇①预处理详解②宏定义③define标识符字符串④define宏名(参数表)字符串⑤宏和函数对比二、调试技巧篇①什么是bug?②调试是什么?有多重要?③debug和release的介绍④windows环境调试介绍⑥如何写出... 查看详情

sublimetext编译运行c语言程序出现无法输入解决办法(windowslinuxmacos均适用)(代码片段)

...imeText编辑器更新到最新版了,在编译处理C或C++语言程序时,发现只要是包含scanf或cin等需要我们手动输入的程序,编译是没问题的,但是在SublimeText里运行会出现无法从命令行输入的情况,在外部运行可... 查看详情

解读:为什么c语言没有重载?(代码片段)

在了解这部分之前,我们需要回顾一下编译链接部分的知识,具体可参考这篇博客:程序的编译与链接接下来我带大家简单回顾一下与我们这部分相关的知识——首先,工程的每一个源文件都是单独编译的,... 查看详情

运行编译型语言是相对于解释型语言存在的(代码片段)

运行编译型语言是相对于解释型语言存在的,编译型语言的首先将源代码编译生成机器语言,再由机器运行机器码(二进制)。像C/C++等都是编译型语言。编译型语言:程序在执行之前需要一个专门的编译过程,把程序编译成为... 查看详情

gcc编译流程(代码片段)

GCC编译器在编译一个C语言程序时需要经过以下4步:将C语言源程序预处理,生成.i文件。预处理后的.i文件编译成为汇编语言,生成.s文件。将汇编语言文件经过汇编,生成目标文件.o文件。将各个模块的.o文件链接起来生成一个... 查看详情

c/c++语言转webassembly篇(代码片段)

官网:https://webassembly.org/EMScripten:https://developer.mozilla.org/en-US/docs/WebAssembly/C_to_wasm(注:这里允许C++语言,但必须以C编译,小心掉坑)C代码#include<stdio.h>#incl 查看详情

第一篇基础原理篇

...:     首先,进行编程,编程需要编程语言,对绝大部分人来说,使用的编程语言称为高级程序设计语言,如,c,c++,java等。但是计算机不认识高级语言编写的程序,编好的程序需要进行编译变成计算机能够识... 查看详情

c++学习基础篇——c++与c语言的区别(代码片段)

...    1980年,BjarneStroustrup博士开始着手创建一种模拟语言,能够具有面向对象的程序设计特色。在当时,面向对象编程还是一个比较新的理念,Stroustrup博士并不是从头开始设计新语言,而是在C语言的基础上... 查看详情

python基础篇:简介(代码片段)

一:简介1.1简介Python是一种用C语言编写的、现代化、弱类型(在声明变量时不需要显式指定数据类型)、脚本语言(解释执行:运行一句,解析一句,而不是编译执行,所以速度相对较慢)、动态语言... 查看详情

面试题java基础篇-常见面试题总结p1(代码片段)

...p1🎈【面试题】Java并发篇-10道常见面试题p11.说说Java语言的特点?Java是一种面向对象的语言Java通过Java虚拟机实现了平台无关性,一次编译,到处运行支持多线程支持网络编程并且很方便具有较高的安全性和可靠... 查看详情

go语言入门篇-命令与语法(代码片段)

一。命令基础1.gorun:用于运行命令源码文件(如:gorunhelloworld.go)只能接受一个命令源码文件以及若干个库源码文件作为文件参数其内部操作步骤:(1)先编译源码文件再运行先会编译作为参数的源码文件-》编译结果放入临时... 查看详情

梦开始的地方——c语言预处理+编译过程(代码片段)

文章目录C语言程序的编译(预处理)1.编译和链接1)编译的几个阶段预编译阶段编译阶段汇编阶段2)链接2.预处理1)预定义符号2)#define3)#和##4)带副作用的宏参数5)宏和函数对比3.常见预处理命令1)#undef2)命令行定义3)条件编译4)文件包含5... 查看详情