GCC编译过程:预处理->编译->汇编->链接

目录

引言

 概括介绍

一、预处理

二、编译

三、汇编

四、链接

总结


引言

当使用集成开发环境(IDE)进行C语言编程时,点击"编译"按钮后,整个C程序从源代码到可执行文件的生成过程会自动完成。IDE会在后台为我们执行C语言的编译过程,将源代码转换为最终的可执行文件。虽然IDE隐藏了底层的细节,但理解编译过程对于程序员来说仍然是很有价值的。

 概括介绍

gccg++都是GNU编译器套件(GNU Compiler Collection,简称GCC)的一部分,其中gcc用于编译C语言代码,而g++用于编译C++语言代码。它们的编译过程在大部分情况下是类似的,但根据输入文件的扩展名和一些默认选项的不同,它们会调用不同的编译器前端,即C前端或C++前端。

下面是gccg++的编译过程的概述

  1. 预处理(Preprocessing):首先,对源文件进行预处理。预处理器将处理源代码中的预处理指令,比如以#开头的指令,如#include#define等,并展开宏定义。预处理后的代码会生成一个.i文件,通常是在临时目录中。

  2. 编译(Compiling):接下来,编译器前端会将预处理后的源代码编译成汇编代码(.s文件)。此阶段会检查语法和语义错误,并进行优化,但不会生成可执行代码。

  3. 汇编(Assembling):汇编器(as)将汇编代码转换成机器代码,并生成目标文件(.o文件)。

  4. 链接(Linking):最后,链接器(ld)将目标文件与所需的库文件链接在一起,生成最终的可执行文件。

下面让我们在Linux环境下简单示例C程序编译过程加深理解

代码示例(main.c):

#include<stdio.h>int main(){printf("Hello Linux\n");return 0;
}

一、预处理

预处理是编译过程的第一步,它处理以#开头的预处理指令,并展开宏定义。预处理器会执行以下主要任务:

  • 处理#include指令:将指定的头文件内容插入到源代码中。这样,可以在源文件中使用其他函数或变量的声明和定义。

  • 处理宏定义:将代码中定义的宏展开为对应的表达式或语句。例如,#define MAX_VALUE 100将会在源代码中把所有MAX_VALUE替换为100

  • 处理条件编译指令:如#ifdef#ifndef#if等,这些指令根据条件判断是否编译部分代码块。

预处理后的代码会生成一个.i文件,这是一个展开了所有宏和包含了所有头文件的中间文件。

语法示例

gcc -E main.c -o main.i

 命令中-E是让编译器在预处理之后就退出,不进行后续编译过程,-o是指定输出文件名。

使用该指令的结果是将stdio.h文件全部内容插入到main.c形成main.i文件。

可以看到预处理之后的main.i文件显然比main.c文件大得多。我们查看一下main.i文件,因为此时main.i依然是文本文件。

(使用head指令查看main.i文件)

二、编译

编译是预处理后代码的第二个阶段。编译器前端(例如cc1cc1plus)接收预处理后的代码,并将其转换成汇编代码。在编译阶段,编译器执行以下主要任务:

  • 语法和语义检查:编译器检查代码是否符合C/C++语法规则,并进行语义分析,以确保代码没有逻辑错误。

  • 生成中间表示:编译器将代码转换成中间表示形式,通常是一种低级的、与特定硬件无关的表示。

  • 优化:编译器可能对中间表示进行优化,以提高程序的执行效率和代码质量。

编译阶段不会生成可执行文件,而是将代码转换成汇编代码,通常保存为.s文件。

语法示例

gcc -S main.i -o main.s

命令中-S让编译器在编译之后停止,不进行后续编译过程,-o是指定输出文件名。

编译成汇编文件大小已经非常小了,相对于预处理之后的main.i文件小很多。

编译过程完成后,将生成程序的汇编代码test.s,这也是文本文件。我们查看一下。

 图中即为main.s中的汇编代码。

三、汇编

在汇编阶段,汇编器(as)接收编译生成的汇编代码,并将其转换为机器代码。汇编器的任务包括:

  • 将汇编代码转换为机器代码:将汇编代码中的汇编指令翻译成特定硬件架构能理解的机器指令。

  • 生成目标文件:生成一个或多个目标文件(.o文件),每个文件对应一个源文件或编译单元。

目标文件是机器代码的二进制表示形式,但它们还不是最终可执行的程序,因为某些符号引用可能仍然未解析。

语法示例

gcc -c main.s -o main.o

命令中-c选项,它告诉gcc只进行编译,不进行链接。因此,这个命令只会将汇编代码转换为目标文件,而不会生成可执行文件。-o是指定输出文件名。

目标文件test.o二进制表示的机器代码,可以作为链接的输入,用于生成最终的可执行文件。

四、链接

  • 链接器接收一个或多个目标文件,以及所需的库文件,并将它们合并成最终的可执行文件。
  • 链接器解析目标文件中的符号引用,找到对应的符号定义,并将符号重定位,以便正确地指向它们的定义。
  • 合并库文件,生成完整的可执行文件,其中包含所有的机器代码和解析后的符号。

语法示例

gcc main.o -o main

命令gcc main.o -o main是将目标文件(main.o)链接为可执行文件(main)的gcc命令。在这个命令中,我们没有使用-c选项,因此gcc会进行链接操作,生成最终的可执行文件。

当执行gcc main.o -o main命令时,gcc会将目标文件main.o与所需的库文件(如果有的话)一起进行链接,并生成最终的可执行文件main。这个可执行文件就是可以在Linux下运行的C程序。

 执行./main命令会运行名为main的可执行文件。这是我们之前用gcc命令生成的C程序的可执行文件。

总结

生成可执行程序过程为成四个步骤:

  1. 由.c文件到.i文件,这个过程叫预处理。
  2. 由.i文件到.s文件,这个过程叫编译。
  3. 由.s文件到.o文件,这个过程叫汇编。
  4. 由.o文件到可执行文件,这个过程叫链接。

在集成开发环境中,点击"编译"按钮后,IDE会自动完成上述四个阶段,无需手动执行每个步骤。如果没有编译错误,最终的可执行文件将生成并可以在IDE中直接运行。

虽然IDE为我们提供了方便的编译工具,但了解C语言的编译过程仍然对于程序员来说是重要的,特别是在解决一些编译错误或进行优化时,理解底层过程可以帮助我们更好地理解和改进代码。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Jwt(Json web token)——使用token的权限验证方法 用户+角色+权限表设计 SpringBoot项目应用

目录 引出使用token的权限验证方法流程 用户、角色、权限表设计权限表角色表角色-权限关联表用户表查询用户的权限&#xff08;四表联查&#xff09;数据库的视图 项目中的应用自定义注解拦截器controller层DTO返回给前端枚举类型的json化日期json问题 实体类-DAO 总结 引出 1.…

Linux usb设备固定端口号

Linux usb设备固定端口号 一:/sys/bus/usb/devices/二:设备信息三:固定usb设备名方法 一:/sys/bus/usb/devices/ 信息显示如下 1-0:1.0 1&#xff1a;表示 1 号总线&#xff0c;或者说 1 号 Root Hub0&#xff1a;表示端口号1&#xff1a;表示配置号0&#xff1a;表示接口号命…

flink+kafka+doris+springboot集成例子

目录 一、例子说明 1.1、概述 1.1、所需环境 1.2、执行流程 二、部署环境 2.1、中间件部署 2.1.1部署kakfa 2.1.1.1 上传解压kafka安装包 2.1.1.2 修改zookeeper.properties 2.1.1.3 修改server.properties 2.1.1.3 启动kafka 2.1.2、部署flink 2.1.2.1 上传解压f…

SpringBoot项目-个人博客系统的实现【下】

10.实现强制要求登陆 当用户访问 博客列表页和 博客详情页时, 如果用户当前尚未登陆, 就自动跳转到登陆页面 1.添加拦截器 public class LoginInterceptor implements HandlerInterceptor {Overridepublic boolean preHandle(HttpServletRequest request, HttpServletRespon…

根文件系统制作

1.官网下载工具 制作工具&#xff1a;busybox https://busybox.net/downloads/ 2.制作根文件系统 2.1准备工作 a.把压缩包放在FSP1M目录下&#xff0c;并解压 2.2正式开始 2.2.1配置交叉编译工具链 1. 打开Makefile文件 2. 修改ARCH &#xff1f;$(SUBARCH) &#xf…

Yolov5缺陷检测/目标检测 Jetson nx部署Triton server

使用AI目标检测进行缺陷检测时&#xff0c;部署到Jetson上即小巧算力还高&#xff0c;将训练好的模型转为tensorRT再部署到Jetson 上供http或GRPC调用。1 Jetson nx 刷机 找个ubuntu 系统NVIDIA官网下载安装Jetson 的sdkmanager一步步刷机即可。 本文刷的是JetPack 5.1, 其中包…

day03

#ifndef __SEQLIST_H__ #define __SEQLIST_H__#include <stdio.h> #include <string.h> #include <stdlib.h>#define MAX 40 typedef int datatype; typedef struct {datatype data[MAX];int len; }seqlist, *seqlistPtr;//创建顺序表 seqlistPtr list_creat…

vscode连接远程Linux服务器

文章目录 一、环境安装1.1 下载vscode1.2 下载vscode-sever 二、ssh链接2.1 安装Remote-SSH2.2 设置vscode ssh2.3 设置免密登录2.3.1 本地生成公私钥2.3.2 服务器端添加公钥 三、安装插件3.1 vscode安装插件3.1.1 在线安装插件3.1.2.1 下载插件3.1.2.2 安装插件 3.2 vscode-se…

Openlayers实战:判断共享单车是否在电子围栏内

共享单车方便了我们的日常生活,解决了后一公里的行程问题。为了解决共享单车乱放的问题,运营部门规划出一些围栏,配合到电子地图上即为电子围栏,只有放在围栏内才能停车结算,在我们的Openlayers实战示例中,即模拟这一场景。 效果图 源代码 /* * @Author: 大剑师兰特(x…

【Git】Git切换地址

如何切换git代码地址&#xff1f; 1、查看当前远程 url git remote -v执行命令后&#xff0c;可以看见当前有2个URL。 远程 URL 在一般情况下有两个&#xff0c;分别是 fetch 和 push。 fetch URL 是用于从远程仓库获取最新版本的数据。当您运行 git fetch 命令时&#xf…

ThreadPoolExecutor线程池详解

ThreadPoolExecutor线程池详解 1. 背景 项目最近的迭代中使用到了ThreadPoolExecutor线程池&#xff0c;之前都只是知道怎么用&#xff0c;没有了解过线程池的底层原理&#xff0c;项目刚上线&#xff0c;有时间整理一下线程池的用法&#xff0c;学习一下线程池的底层实现与工…

运行 Jmeter 文件生成 HTML 测试报告,我选择 ANT 工具

概述 ant 是一个将软件编译、测试、部署等步骤联系在一起加以自动化的一个工具&#xff0c;大多用于 Java 环境中的软件开发。 在与 Jmeter 生成的 jmx 文件配合使用中&#xff0c;ant 会完成jmx计划的执行和生成jtl文件&#xff0c;并将jtl文件转化为html页面进行查看。 还可…

Node.js |(三)Node.js API:path模块及Node.js 模块化 | 尚硅谷2023版Node.js零基础视频教程

学习视频&#xff1a;尚硅谷2023版Node.js零基础视频教程&#xff0c;nodejs新手到高手 文章目录 &#x1f4da;path模块&#x1f4da;Node.js模块化&#x1f407;介绍&#x1f407;模块暴露数据⭐️模块初体验⭐️暴露数据 &#x1f407;导入文件模块&#x1f407;导入文件夹的…

CAPL - XML和TestModule结合实现测试项可选

目录 目的:是否想实现如下面的功能呢? 一、.can和.cin文件中函数开发

C/C++面试总结

一、关键字static、const、extern、volatile作用 1、const 1.修饰常量 用const修饰的变量是不可变的&#xff0c;修饰后的变量只能使用&#xff0c;不能修改。 2.修饰指针 如果const位于*的左侧&#xff0c;eg&#xff1a;const int* a&#xff0c;则const就是用来修饰指针…

研发工程师玩转Kubernetes——hostPath

有别于《研发工程师玩转Kubernetes——emptyDir》一文中介绍的emptyDir&#xff0c;hostPath可以在同一个Node的不同Pod间共享卷。 下面的清单文件利用了Pod亲和性&#xff0c;让Pod集中到一个Node上。 apiVersion: apps/v1 kind: Deployment metadata:name: hostpath-deploy…

Adobe ColdFusion 反序列化漏洞复现(CVE-2023-29300)

0x01 产品简介 Adobe ColdFusion是美国奥多比&#xff08;Adobe&#xff09;公司的一套快速应用程序开发平台。该平台包括集成开发环境和脚本语言。 0x02 漏洞概述 Adobe ColdFusion存在代码问题漏洞&#xff0c;该漏洞源于受到不受信任数据反序列化漏洞的影响&#xff0c;攻击…

FinClip 支持小程序维度域名配置;桌面端体验活动进行中

FinClip 的使命是使您&#xff08;业务专家和开发人员&#xff09;能够通过小程序解决关键业务流程挑战&#xff0c;并完成数字化转型的相关操作。不妨让我们看看在本月的产品与市场发布亮点&#xff0c;看看是否有助于您实现目标。 产品方面的相关动向&#x1f447;&#x1f…

Kafka概论

前言 任何消息中间件&#xff0c;除了基础组件架构外&#xff0c;核心特性无非三个&#xff0c;消息可靠性、消息模型、吞吐量&#xff0c;本文要聊的正是这些东西&#xff0c;其余诸如API、下载安装、集群搭建等都是死的&#xff0c;而且会随着版本的变动而改变&#xff0c;这…

uni-app 封装api请求

前端封装api请求 前端封装 API 请求可以提高代码的可维护性和重用性&#xff0c;同时使得 API 调用更加简洁和易用。 下面是一种常见的前端封装 API 请求的方式&#xff1a; 创建一个 API 封装模块或类&#xff1a;可以使用 JavaScript 或 TypeScript 创建一个独立的模块或类来…