IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> C++从代码到可执行程序过程(预编译、编译、汇编、链接) -> 正文阅读

[C++知识库]C++从代码到可执行程序过程(预编译、编译、汇编、链接)

C++从代码到可执行程序

预编译

主要处理以“#”开头的预编译指令

  • 删除所有的#define,展开所有的宏定义
  • 处理所有的条件预编译指令,如#if、#endif、#ifdef、#elif、#else
  • 处理#include预编译指令,将文件内容替换到它的位置,递归进行,文件中包含其他文件
  • 删除所有的注释
  • 保留所有的#pragma编译指令,编译器需要用到它们。如pragma once是为了防止有文件被重复引用
  • 添加行号和文件标识,便于编译时编译器产生调试用的行号信息,和编译时产生编译错误或警告时能够显示行号

编译

把预编译生成的.i或者.ii文件,进行一系列词法分析、语法分析、语义分析、优化后,生成相应的汇编代码文件

  • 词法分析:利用类似有限状态机的算法,将源代码程序输入到扫描机中,将其中的字符序列分割成一系列的记号
  • 语法分析:语法分析器对由扫描器产生的记号,进行语法分析,产生语法树。由语法分析器输出的语法树是一种以表达式为节点的树
  • 语义分析:语法分析器只是完成了对表达式语法层面的分析,语义分析器则对表达式是否有意义进行判断,其分析的语义是静态语义(在编译期能分析),相对应的动态语义是在运行期间才能确定
  • 优化:源代码级别的一个优化过程
  • 目标代码生成:由代码生成器将中间代码转换成目标机器代码(汇编语言)
  • 目标代码优化:对目标机器代码进行优化,寻找合适的寻址方式、使用位移来代替乘法运算、删除多余的指令

汇编

将汇编代码转换成机器可以执行的指令(机器码文件),汇编器的汇编过程相对于编译器来说更简单,没有复杂的语法,也没有语义,更不需要做指令优化,只是根据汇编指令和机器指令对照表翻译过来,经过汇编之后,产生目标文件(与可执行文件几乎一样)

链接

将不同的源文件产生的目标文件进行链接,从而形成一个可以执行的程序

链接分为静态链接和动态链接:

静态库可能是源代码,动态库可能本身就是一个可执行文件

  • 静态链接:静态库 libxxx.o、libxxx.a

    • 函数和数据被编译进一个二进制文件

    • 使用静态库的情况下,在编译链接可执行文件时,链接器从库中复制这些函数和数据并把它们和应用程序的其他模块组合起来创建最终的可执行文件

    • 每当库函数的代码修改了,需要重新进行编译链接形成可执行文件

    • 优点:运行速度快,代码装载速度快

    • 缺点

      • 编译生成的程序体积会相对大一些
      • 如果静态库需要更新,程序需要重新编译
      • 如果多个应用程序使用的话,会被装载多次,浪费内存
    • 静态链接打包命令

      gcc -c test1.c	//生成test1.o
      gcc -c test2.c	//生成test2.o
      ar cr libtest.a test1.o test2.o
      

      首先编译得到test1.o和test2.o两个目标文件,之后通过ar命令将这两个文件打包为.a文件,文件名格式为lib + 静态库名 + .a后缀。在生成可执行文件需要使用到它的时候只需要在编译时加上即可。需要注意的是,使用静态库时加在最后的名字不是libtest.a,而是l + 静态库名

      gcc -o main main.c -ltest
      
  • 动态链接:动态库 libxxx.so

    • 把程序按照模块拆分成各个相对独立部分,在程序链接时才将它们链接在一起形成一个可执行文件

    • 共享库:即使每个程序都依赖同一个库,但是该库不会像静态链接那样在内存中存多份副本,而是多个程序在执行时共享同一份

    • 更新方法:更新的时候只需要替换原来的目标文件,无需将所有程序重新编译链接一遍。当程序下次运行时,新版本的目标文件会被自动加载到内存并链接起来

    • 缺点:每次执行程序的时候进行链接,性能会有一定的损失

    • 动态链接在形式上倒是和静态链接非常相似,首先也是需要打包,打包成动态库,不过文件格式为libxxx.so。动态库的打包不需要使用ar命令,gcc就可以完成,但要注意在编译时要加上-fPIC选项,打包时加上-shared选项。

      gcc -fPIC -c test1.c 
      gcc -fPIC -c test2.c
      gcc -shared test1.o test2.o -o libtest.so
      

      使用动态链接的用法也和静态链接相同

      gcc -o main main.c -ltest
      

      如果仅仅像上面的步骤是没有办法正常使用库的,我们可以通过加-Lpath指定搜索库文件的目录(-L.表示当前目录),默认情况下会到环境变量LD_LIBRARY_PATH指定的目录下搜索库文件,默认情况是/usr/lib,我们可以将库文件拷贝到那个目录下再链接。

Makefile编写

对于大的工程通常涉及很多头文件和源文件,编译起来很麻烦,Makefile正是为了自动化编译产生的,Makefile像是编译说明书,指示编译的步骤和条件,之后被make命令解释。

  • 基本规则
A:B
(tab)<command>

其中A是语句最后生成的文件,B是生成A所依赖的文件,比如生成test.o依赖于test.h,则写成test.o:test.c test.h。接下来一行的开头必须是tab,再往下就是实际命令了,比如gcc -c test.c -o test.o

  • 变更

Makefile的书写非常像shell脚本,可以在文件中定义“变量名 = 变量值”的形式,之后需要使用这个变量时只需要写一个$符号加上变量名即可,当然和shell一样最好用()包裹起语句来

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2021-08-17 15:11:24  更:2021-08-17 15:11:54 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年12日历 -2024/12/26 16:29:21-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码
数据统计