基于Linux下gcc学习C/C++——编译过程

  • 前提:WSL2(Ubuntu)、gcc编译器。
  • gcc安装命令:
    • sudo apt-get install gcc
  •  查看gcc版本:

目录

1、编译过程

1.1、预处理

1.2、编译与汇编

1.3、链接

2、gcc实验

2.1、预处理

2.2、编译

2.3、汇编

2.4、链接


1、编译过程

  • 对于c/c++编程,从源代码文件变成可执行文件,大致需要以下几步:
    • 预处理 (Pre-Processing)
      • 预处理器处理#include、#define等内容,把头文件复制到源文件中等。
    • 编译 (Compiling)
      • 得到以汇编语言写的,可读的文件。
    • 汇编 (Assembling)
      • 得到二进制格式,不可读的文件。
      • 编译和汇编主要是分析源代码中的内容,然后转换为目标文件。
    • 链接 (Linking)
      • ​​​​​​​静态库和动态库的处理体现在链接过程中,链接器把目标文件和库一起打包变成可执行文件。
    • 【注】c/c++的编译过程和java、python等语言不同。

1.1、预处理

  • 预处理主要的工作包括:
    • 文件包含,通常包括系统的头文件和自定义的头文件。
    • 宏定义的处理,例如,#define PI 3.14,替换相应的内容。
    • 条件编译,例如,#ifdef、#ifndef、#else、#elif、#endif等,可以结合宏的使用实现部分编译,防止头文件重复包含等。
    • 特殊控制,例如#pragma命令,#error命令等。
    • 添加行号和文件名标识,清理注释内容等。
  • 预处理指令不属于C/C++语言的标准语法,一定意义上也可以说预处理扩展了C/C++,因此预处理的具体语法和实现,与编译器以及平台相关。

1.2、编译与汇编

  • 这是编译过程的核心部分,主要步骤有:
    • 词法分析
    • 语法分析
    • 语义分析
    • 代码优化
  • 到这一步为止,我们从源文件 (和头文件) 得到了目标文件,通常每一个源文件都应该对应产生一个目标文件。下一阶段是链接,会把目标文件和库文件结合在一起,得到可执行文件 (二进制程序)。
  • 为了得到正确的目标文件,这个环节重点检查:语法的正确函数以及变量的声明和使用的正确。
    • 【注】这一阶段,只要能在头文件中找到正确的声明即可,并不负责检查外部函数和变量是否被正确实现和定义,可以接收空头支票。
  • 与之不同的是,下一阶段的链接器并不对源文件进行操作,它面对的就是目标文件和库文件,这个环节需要重点检查的是跨文件的符号 (外部函数和外部变量) 是否都被实现,并且把它们合并到一起 (它需要检查,编译时开出的空头支票是否都被兑现),如果出现了符号未定义或者符号重复定义,就会报链接错误。

1.3、链接

  • 链接就是将目标文件和库文件打包、组装成可执行文件的过程。这里库文件就是早已完成的,可重复使用的成熟组件,而刚刚实现的源文件已经被处理为目标文件,等待着被一起打包组装。
  • 链接环节要解决的问题是,怎么让各个不同的模块可以一起工作。有的文件中使用的符号在另一个文件中定义,有的函数具体在另一个文件中实现。链接需要让它们互相认识,重定位,确定符号的对应关系,统一进行地址分配等。
    • 例如,hello.c源文件使用了printf这个函数,通过stdio.h这个头文件中的函数声明可以明白它的用法,但是它的具体实现其实是在动态库libc.so.6,链接的时候需要引用这个库文件。
  • 根据指定的链接库函数的方式不同,链接过程可分为静态链接和动态链接两种。选择静态链接时,相当于把库中需要用到的部分直接拷贝过来;选择动态链接时,相当于仅仅登记一下库的基本信息,等执行的时候再去查找和加载动态库。
    • 静态链接:从库中将需要用到的部分内容直接拷贝到最终的可执行程序中。
      • 优点:可执行文件一旦生成,就与这个库没有联系,自己可以独立运行。
      • 缺点:可执行文件体积较大,有很多重复的空间占用;如果更新升级库中的功能,则所有用到这个库的可执行文件必须重新编译。
    • 动态链接:编译时暂时记录一下动态库的基本信息,但不会拷贝其中的具体内容,等到运行时再去寻找需要的动态库,将其加载到内存中一起执行。
      • 优点:可执行文件体积较小,可以节约空间,多个程序可以共同利用同一个基础的动态库;可以灵活升级动态库的功能,如果保证二进制层面的兼容性,那么用到它的相关程序不需要重新编译。
      • 缺点:可执行文件执行时仍然需要这个动态库,执行时很可能遇到动态库找不到,动态库版本不兼容等问题。
  • 由于两种链接方式对应的文件格式不同,一个具体的库只能被动态链接或只能被静态链接。通常的库可以提供静态库版本和动态库版本,可以灵活选择。
  • gcc如果同时找到了一个库的静态库版本和动态库版本,默认情况下会使用动态库,进行动态链接。 

2、gcc实验

  • 创建c文件:
    • mkdir project01  # 创建存放c文件的文件夹
      cd project01  # 进入文件夹
      vim hello.c  # 创建并编写c文件
  • 编写hello.c: 
    • 按 i,进入插入模式,编辑文件。
    • 编辑完毕后按回退键,输入 :wq,保存文件。

2.1、预处理

  • 对于gcc来说,它会调用一个叫cpp的预处理工具,全称为C Pre-Processor (C 预处理器),是一个与C编译器独立的小程序,注意不是C Plus Plus。
  • gcc使用-E选项可以让编译过程在预处理步骤完成之后停止。
    • gcc -E hello.c -o hello.i
  • 【注】必须指明输出到文件hello.i,否则会把预处理结果直接输出到终端,建议的文件后缀为 .i。
  • 查看hello.i文件。
    • 得到的hello.i文件内容很长,仍然是可读的。文件前面的绝大部分都是头文件中的,原本的hello.c的内容在最后几行​​​​​​​。

2.2、编译

  • 这是整个编译过程的核心步骤,gcc调用的处理程序一般是cc。
  • gcc使用-S选项可以让编译过程在编译步骤完成之后停止。
    • gcc -S hello.c -o hello.s
      # 不加-o可以默认生成同名.s 汇编文件hello.s
      # 加-o选项则可以自定义输出文件名
      
      gcc -S hello.i -o hello.s
      # 对.c或者.i文件都可以执行上述命令,效果一样
  • 查看hello.s文件,即汇编语言文件。

2.3、汇编

  • gcc在这一环节调用的工具通常是as。
  • gcc使用-c选项可以让编译过程在编译步骤完成之后停止。
    • gcc -c hello.c -o hello.o
      # 使用-c选项会让gcc在第三步汇编之后就暂停
      # 不使用-o选项会默认生成同名的.o目标文件
      
      gcc -c hello.i -o hello.o
      gcc -c hello.s -o hello.o
      # 同样可以从.i .s中间文件出发,效果也是一样的
  • 得到的是二进制格式的目标文件。

2.4、链接

  • 链接过程是程序构建过程的最后一步,通常gcc调用ld来完成。
  • 链接指的是把目标文件组合起来,变成可执行文件。由于当前例子只有单个文件,没有库文件,只会自动链接系统的一些库,暂时不需要关注这些细节。
  • gcc hello.o -o hello
    # 从目标文件得到可执行文件
    
    gcc hello.o
    # 省略-o选项相当于 -o a.out
    
    gcc hello.c
    gcc hello.i
    gcc hello.s
    # 同样可以从.c .i .s文件出发,效果也一样
  • 【注】gcc可以编译c++文件,但是不能自动链接c++程序使用的库,所以一般使用g++编译c++程序。 
    • 但是也可以使用gcc手动链接c++库,具体看:用gcc编译C++文件_gcc可以编译c++吗-CSDN博客
  •  生成的hello为可执行文件,直接运行即可。
    • ./hello
    •  

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/263681.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Win系统修改Nginx配置结合内网穿透实现远程访问多个Web站点

文章目录 1. 下载windows版Nginx2. 配置Nginx3. 测试局域网访问4. cpolar内网穿透5. 测试公网访问6. 配置固定二级子域名7. 测试访问公网固定二级子域名 1. 下载windows版Nginx 进入官方网站(http://nginx.org/en/download.html)下载windows版的nginx 下载好后解压进入nginx目…

[笔记]netty随笔

记录使用过程中偶然发现的一些关键逻辑。先做记录,以后netty知识有一定体系再做整理 childGroup 服务器中有俩group,一个是parentGroup,负责处理链接请求,一个是childGroup,负责业务逻辑。 channelActive是在childG…

Spring中你一定要知道的@PostConstruct/@PreDestroy

文章目录 功能源码解析执行 功能 Spring中存在很多回调,但是执行他们的时机都不相同,也许大家用的最多的是InitializingBean.afterPropertiesSet,这个方法的作用如名称一样,是bean初始化后执行的一个回调操作,而PostC…

C语言学习NO.9-指针(一)内存和地址,指针变量和地址,指针变类型的意义,const修饰指针,指针运算,野指针,assret断言,指针的使用和传址调用

指针是什么? 指针是什么? 指针理解的2个要点: 1.指针是内存中一个最小单元的编号,也就是地址; 2.平时口语中说的指针,通常指的是指针变量,是用来存放内存地址的变量。 总结:指针就是…

MySQL中CASE when 实战

CASE 语法 CASEWHEN condition1 THEN result1WHEN condition2 THEN result2WHEN conditionN THEN resultNELSE result END; 将表中的内容转换为右边的形式: 1、创建表,创建数据 CREATE TABLEchapter10_7 (order_id VARCHAR(255) NULL,price VARCHAR(25…

手写题 - 实现一个带并发限制的异步调度器

题目 实现一个带并发限制的异步调度器 Scheduler,保证同时运行的任务最多有N个。 完善下面代码中的 Scheduler 类,使得以下程序能正确输出:class Scheduler {add(promiseCreator) { ... }// ... }const timeout (time) > new Promise(re…

从零学算法5

5.给你一个字符串 s,找到 s 中最长的回文子串。 如果字符串的反序与原始字符串相同,则该字符串称为回文字符串。 示例 1: 输入:s “babad” 输出:“bab” 解释:“aba” 同样是符合题意的答案。 示例 2&…

Vue中为什么data属性是一个函数而不是一个对象?(看完就会了)

文章目录 一、实例和组件定义data的区别二、组件data定义函数与对象的区别三、原理分析四、结论 一、实例和组件定义data的区别 vue实例的时候定义data属性既可以是一个对象,也可以是一个函数 const app new Vue({el:"#app",// 对象格式data:{foo:&quo…

springboot学习笔记(五)

MybatisPlus进阶 1.MybatisPlus一对多查询 2.分页查询 1.MybatisPlus一对多查询 场景:我有一个表,里面填写的是用户的个人信息(姓名,生日,密码,用户ID)。我还有一个表填写的订单信息&#x…

Linux系统管理、服务器设置、安全、云数据中心

前言 「作者主页」:雪碧有白泡泡 「个人网站」:雪碧的个人网站 我们来快速了解liunx命令 文章目录 前言解析命令提示符linux的文件和目录文件和目录管理文件操作 进程管理命令系统管理网络管理 书籍推荐 本文以服务器最常用的CentOS为例 解析命令提示…

图片怎么转文字?这几个图片提取文字方法教会你!

在数字时代,我们每天都与大量的图片、文本信息打交道。当我们需要从图片中提取文字时,传统的方式可能是手动输入或者借助某些付费工具,今天介绍这三个工具不仅易于使用,而且效果卓越,我只需上传图片,工具便…

uniapp地图开发(APP,H5)

uniapp地图开发(APP,H5) 背景实现页面实现功能实现注意事项 尾巴 背景 最近项目中需要使用地图相关功能,需要用到聚合,marker拖拽,自定义marker显示内容,根据角色不同maker显示不同图标等功能。…

Nacos教程

常见的微服务架构: 1. dubbo: zookeeper dubbo SpringMVC/SpringBoot 配套 通信方式:rpc 注册中心:zookeeper / redis 2.SpringCloud : 全家桶 轻松嵌入第三方组件 (Netflix) 配套 通信方式:http restful 注册中心…

【MATLAB】史上最全的13种数据拟合算法全家桶

有意向获取代码,请转文末观看代码获取方式~ 1 【MATLAB】傅里叶级数拟合算法 傅里叶级数拟合算法是一种强大而灵活的数学方法,可以将复杂的函数拆解成多个简单的正弦和余弦函数的和。通过求解函数中的系数,我们可以用有限项傅里叶级数来拟合…

类和对象(下篇)

再谈构造函数 构造函数体赋值 在之前的学习中我们知道,在创建一个对象时,我们的编译器就会自动调用构造函数将对象初始化,给对象中各个成员变量一个合适的初始值。 例如: class Date { public:Date(int year, int month, int d…

Java文件流大家族(通俗易懂,学习推荐版,很详细)——操作文件本身和文件中的数据

1.File(操作文件本身) 1.定义 目录 2.常用方法 3.路径引用符 可以用/或者\\分隔路径 还可以用File.separator分隔路径,会根据不同系统使用啥分隔符。 4.绝对路径、相对路径及桌面路径表示 桌面路径为: 我电脑的用户名为X 5.示例…

服务器数据恢复-误操作导致xfs分区数据丢失的数据恢复案例

服务器数据恢复环境: 某品牌OceanStorT系列某型号存储MD1200磁盘柜,组建的raid5磁盘阵列。上层分配了1个lun,安装的linux操作系统,划分两个分区,分区一通过lvm进行扩容,分区二格式化为xfs文件系统。 服务器…

初级数据结构(七)——二叉树

文中代码源文件已上传&#xff1a;数据结构源码 <-上一篇 初级数据结构&#xff08;六&#xff09;——堆 | NULL 下一篇-> 1、写在前面 二叉树的基本概念在《初级数据结构&#xff08;五&#xff09;——树和二叉树的概念》中已经介绍得足够详细了。上一…

海康威视对讲广播系统 RCE漏洞复现(CVE-2023-6895)

0x01 产品简介 Hikvision Intercom Broadcasting System是中国海康威视(Hikvision)公司的一个对讲广播系统。 0x02 漏洞概述 Hikvision Intercom Broadcasting System 3.0.3_20201113_RELEASE(HIK)版本存在操作系统命令注入漏洞,该漏洞源于文件/php/ping.php的参数jsonda…

虾皮跨境电商物流:打造高效便捷的全球供应链解决方案

随着全球化的推进和电子商务的蓬勃发展&#xff0c;跨境电商物流成为了越来越多商家和消费者关注的焦点。虾皮&#xff08;Shopee&#xff09;作为一家领先的电商平台&#xff0c;不仅提供了丰富多样的商品选择&#xff0c;还致力于为卖家和消费者提供高效便捷的跨境电商物流服…