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语言的编译过程仍然对于程序员来说是重要的,特别是在解决一些编译错误或进行优化时,理解底层过程可以帮助我们更好地理解和改进代码。

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

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

相关文章

微服务——es数据聚合+RestClient实现聚合

数据聚合 聚合的种类 DSL实现Bucket聚合 如图所示&#xff0c;设置了10个桶&#xff0c;那么就显示了数量最多的前10个桶&#xff0c;品牌含有7天酒店的有30家&#xff0c; 品牌含有如家的也有30家。 修改排序规则 限定聚合范围 DSL实现Metrics聚合 如下案例要求对不同的品…

【Go 基础篇】Go语言初探:第一段代码与执行过程解析

介绍 Go语言&#xff08;也称为Golang&#xff09;作为一门现代化的编程语言&#xff0c;以其简洁的语法、高效的性能和丰富的标准库而受到了广泛关注和使用。对于初学者来说&#xff0c;编写和执行第一段Go代码是迈向这门语言的重要一步。本篇博客将带您深入了解Go语言的第一…

来讲一讲面试必问的异步FIFO设计!

异步FIFO设计可以说是数字IC设计工程师面试时必问的一个问题了&#xff0c;也是我们经常使用但是又往往被忽略的一个东西&#xff0c;今天就展开详细说一说不同深度&#xff08;2^N或者非2^N&#xff09;异步FIFO的设计思想&#xff1b; 一&#xff1a;2^N深度异步FIFO设计 1…

git和github学习

一、什么是git和github? 二、学会使用github desktop应用程序 初始使用&#xff1a; 一开始我们是新账户&#xff0c;里面是没有仓库的&#xff0c;需要手动创建一个仓库。此时&#xff0c;这个仓库是创建在本地仓库里面&#xff0c;需要用到push命令&#xff08;就是那个pub…

现代C++中的从头开始深度学习【2/8】:张量编程

一、说明 初学者文本&#xff1a;此文本需要入门级编程背景和对机器学习的基本了解。张量是在深度学习算法中表示数据的主要方式。它们广泛用于在算法执行期间实现输入、输出、参数和内部状态。 在这个故事中&#xff0c;我们将学习如何使用特征张量 API 来开发我们的C算法。具…

Android Studio实现简单ListView

效果图 MainActivity package com.example.listviewtest;import androidx.appcompat.app.AppCompatActivity;import android.os.Bundle; import android.widget.ListView;import com.example.listviewtest.adapter.PartAdapter; import com.example.listviewtest.bean.PartB…

【Spring Cloud 六】Hystrix熔断

这里写目录标题 系列文章目录背景一、Hystrix是什么服务雪崩服务容错的相关概念熔断器降级超时控制限流 二、会什么要有Hystrix三、如何使用Hystrix进行熔断处理整体项目代码服务提供者pom文件yml配置文件启动类controller 服务消费者pom文件yml配置文件启动类feignhystrixcont…

网络安全(黑客)零基础入门

导语 什么是 Web 安全&#xff1f;我又该如何入门学习它呢&#xff1f;学习过程中又应注意哪些问题呢&#xff1f;... 或许你的心中有着这样的疑问、不过别着急&#xff0c;本文会为你一一解答这些问题。 正文 定义 Web 安全&#xff0c;顾名思义便是由保障 Web 应用能够持续…

Windows新版文件资源管理器经常在后台弹出的临时解决方案

禁用组策略自动刷新 运行gpedit.msc找到计算机配置->管理模板->系统->组策略找到 “关闭组策略的后台刷新”启用 参考 https://answers.microsoft.com/en-us/windows/forum/all/windows-11-most-recently-opened-explorer-window/26e097bd-1eba-4462-99bd-61597b5…

【计算机网络】socket编程

文章目录 1. 网络通信的理解2.进程PID可以取代端口号吗&#xff1f;3. 认识TCP协议4. 认识 UDP协议5. socket编程接口udp_server.hpp的代码解析socket——创建 socket 文件描述符Initserver——初始化1.创建套接字接口&#xff0c;打开网络文件bind——绑定的使用 2.给服务器指…

鸿蒙智联再出发,携手伙伴共赢空间智能化,创造无限可能

新空间&#xff0c;再出发&#xff0c;HarmonyOS Connect伙伴峰会完 2023年8月5日&#xff0c;HarmonyOS Connect伙伴峰会在东莞如期举办&#xff0c;峰会以《一起创造无限可能 新空间 再出发》为主题&#xff0c;深度解读了鸿蒙智联商业模式全面升级以来&#xff0c;给伙伴带来…

Qt拖放事件与拖放操作笔记dragEnterEvent,dropEvent

1 介绍 拖放事件主要用于处理MIME数据&#xff0c;该数据是用于在发送电子邮件时&#xff0c;附加多媒体数据&#xff08;即拖拽一个文件放入邮件中&#xff0c;事件文件的上传&#xff09;。 2 示例 a&#xff09;使用简化步骤声明拖放事件成员函数&#xff1a; b&#xff09;…

C#与C/C++交互(1)——需要了解的基础知识

【前言】 C#中用于实现调用C/C的方案是P/Invoke&#xff08;Platform Invoke&#xff09;&#xff0c;让托管代码可以调用库中的函数。类似的功能&#xff0c;JAVA中叫JNI&#xff0c;Python中叫Ctypes。 常见的代码用法如下&#xff1a; [DllImport("Test.dll", E…

IPv6地址分类,EUI-64转换规则

1、可聚合的单全球单播地址Global Unique Address&#xff1a; Aggregate global unicast address&#xff0c;前3位是001&#xff0c;即2000::/3&#xff0c;目前IANA已经将一部分可聚合全球单播进行了专门使用&#xff0c;如&#xff1a;2001::/16用于IPV6互联网&#xff0c;…

流量分析日志查看

一流量分析 buuctf wireshark 从题目出发&#xff0c;既然是上传登录信息&#xff0c;就直接过滤post请求&#xff0c;即搜索 http.request.methodPOST&#xff0c;因为上传用户登录信息使用的一定是http里的post方法 模式过滤 http.request.method “GET” http.request.…

无涯教程-Perl - getpriority函数

描述 此函数返回进程(PRIO_PROCESS),进程组(PRIO_PGRP)或用户(PRIO_USER)的当前优先级。 参数WHICH指定要为PRIO_PROCESS,PRIO_PGRP或PRIO_USER之一设置优先级的实体,WHO是要设置的进程ID或用户ID。 WHO的值为0定义了当前流程,流程组或用户。这会在不支持系统getpriority()函…

Springboot后端通过路径映射获取本机图片资源

项目场景&#xff1a; 项目中对图片的处理与查看是必不可少的&#xff0c;本文将讲解如何通过项目路径来获取到本机电脑的图片资源 如图所示&#xff0c;在我的本机D盘的图片测试文件夹(文件夹名字不要有中文)下有一些图片&#xff0c; 我们要在浏览器上访问到这些图片&#…

RISC-V基础之函数调用(二)栈与寄存器(包含实例)

堆栈是一种后进先出&#xff08;LIFO&#xff09;的队列&#xff0c;用于存储函数调用时的临时数据和现场数据。堆栈指针sp&#xff08;寄存器2&#xff09;是一个普通的RISC-V寄存器&#xff0c;按照惯例&#xff0c;指向堆栈的顶部。堆栈从高地址向低地址增长&#xff0c;即当…

【UE4 RTS】04-Camera Pan

前言 本篇实现了CameraPawn的旋转功能。 效果 步骤 1. 打开项目设置&#xff0c;添加两个操作映射 2. 打开玩家控制器“RTS_PlayerController_BP”&#xff0c;新建一个浮点型变量&#xff0c;命名为“PanSpeed” 在事件图表中添加如下节点 此时运行游戏可以发现当鼠标移动…

WEB集群——负载均衡集群

目录 一、 LVS-DR 群集。 1、LVS-DR工作原理 2、LVS-DR模式的特点 3、部署LVS-DR集群 3.1 配置负载调度器&#xff08;192.168.186.100&#xff09; 3.2 第一台web节点服务器&#xff08;192.168.186.103&#xff09; 3.3 第二台web节点服务器&#xff08;192.168.186.…