GCC编译器的使用

news2025/1/13 8:03:27

源文件需要经过编译才能生成可执行文件。GCC是一款强大的程序编译软件,能够在多个平台中使用。

1. GCC编译过程

主要分为四个过程:预处理、编译、汇编、链接。
在这里插入图片描述

1.1 预处理

主要处理源代码文件中以#开头的预编译指令。 处理规则有:

(1)删除所有的 #define,展开所有的宏定义。

(2)处理所有的条件预编译指令,如#if、#endif、#ifdef、#elif、和#else。

(3)处理 #include 预编译指令,将文件内容替换到它的位置,这个过程是递归进行的,文件中包含了其他文件。

(4)删除所有的注释。

(5)保留所有 #pragma 编译器指令,编译器需要用到它们。比如,#pragme once 是为了防止有文件被重复引用。

(6)添加行号和文件标识,便于编译时编译器产生调试用的行号信息,和编译时产生编译错误或警告时,能够显示行号。

1.2 编译

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

(1)词法分析:利用类似于“有限状态机”的算法,将源代码程序输入到扫描机中,将其中的字符序列分割成一系列的记号。

(2)语法分析:语法分析器对扫描器产生的记号,进行语法分析,产生语法树。由语法分析器输出的语法树是一种以表达式为节点的树。

(3)语义分析:语法分析器只是完成了对表达式语法层面的分析,语义分析器则对表达式是否有意义进行判断,其分析的语义是静态语义,也就是在编译期能分析的语义。相对应的动态语义是在运行期才能确定的语义。

(4)优化:源代码级别的一个优化过程。

(5)目标代码生成:由代码生成器 将中间代码转换成目标机器代码,生成一系列由汇编语义表示的代码序列。

(6)目标代码优化:目标代码优化器 对上述的目标机器代码进行优化:寻找合适的寻址方式、使用位移来代替乘法运算、删除多余的指令等。

1.3 汇编

将汇编代码转变成机器可以执行的指令(机器码文件)。汇编器的汇编过程相对于编译器来说更简单,没有复杂的语法,也没有语义,更不需要做指令优化,只有根据汇编指令和机器指令的对照表翻译过来。汇编过程是由汇编器完成。

经汇编之后,产生目标文件,Linux下是.o文件,windows下是.obj文件。

1.4 链接

将不同的源文件产生的目标文件进行链接,从而生成一个可以执行的程序。链接分为静态链接和动态链接。

静态链接

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

缺点是空间浪费,因为每个可执行文件中对所需的目标文件都要有一个副本,所以如果多个程序对同一目标文件都有依赖,会出现同一个目标文件在内存中存在多个副本。

还有一个缺点是更新困难,每当库函数代码修改了,这个时候就需要重新进行编译链接生成可执行程序。

优点是运行速度快,在可执行程序中已经具备了所有执行程序所需要的任何东西,在执行的时候运行速度快。

动态链接

动态链接的基本思想是把程序按照模块拆分成各个相对独立的部分,在程序运行时才将它们链接在一起形成一个完整的程序,而不是像静态链接一样把所有的程序模块都链接成一个单独的可执行文件。

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

更新方便:更新时只需要替换原来的目标文件,而无需将所有的程序再重新链接一遍。当程序下一次运行时,新版本的目标文件会被自动加载到内存并且链接起来,程序就完成了升级的目标。

性能损耗:因为把链接推迟到了程序运行时,每次执行程序都需要进行链接,所以性能会有一定的损失。

2. GCC编译命令

最常用的gcc编译命令为:

# -o是输出的意思 输出名为hello的可执行程序,然后可以执行./hello
gcc -o hello hello.c

gcc使用示例:

gcc hello.c                   // 输出一个名为a.out的可执行程序,然后可以执行./a.out
gcc -o hello hello.c          // 输出名为hello的可执行程序,然后可以执行./hello
gcc -o hello hello.c -static  // 静态链接

gcc -c -o hello.o hello.c  	  // 先编译(不链接)
gcc -o hello hello.o          // 再链接

可以通过不同的gcc选项控制gcc编译过程,将gcc编译过程拆分。

# 只进行预处理,生成.i文件
gcc -E -o hello.i hello.c
# 只进行编译操作,将.i文件生成.s的汇编文件
gcc -S -o hello.s hello.i
# 只进行汇编操作,将.s文件生成.o文件
gcc -c -o hello.o hello.s
# 只进行链接操作,将.o文件进行链接,生成最终的可执行文件
gcc -o hello hello.o

如图所示,为各命令将gcc编译过程进行拆分。
在这里插入图片描述

执行gcc -o hello hello.c -v时,可以查看到整个gcc编译步骤,可以结合上图进行理解。

# cc1命令完成预处理与编译操作
cc1 main.c -o /tmp/ccXCx1YG.s
# as命令完成汇编操作
as -o /tmp/ccZfdaDo.o /tmp/ccXCx1YG.s
 
cc1 sub.c -o /tmp/ccXCx1YG.s
as -o /tmp/ccn8Cjq6.o /tmp/ccXCx1YG.s

#collect2命令将生成的所有.o文件进行链接,生成可执行文件test
collect2 -o test /tmp/ccZfdaDo.o /tmp/ccn8Cjq6.o ....

3. 常用编译选项

常用选项描述
-E预处理,开发过程中想快速确定某个宏可以使用“-E -dM”
-c把预处理、编译、汇编都做了,但是不链接
-o指定输出文件
-I(i的大写)指定头文件目录
-L指定链接时库文件目录
-l(L的小写)指定链接哪一个库文件

例如,使用 -I 参数指定头文件目录

# 头文件目录为当前目录 ./
gcc -c -o main.o main.c -I ./

4. 编译多个文件

(1)一起编译、链接

gcc  -o test  main.c  sub.c

(2)分开编译,统一链接

gcc -c -o main.o  main.c
gcc -c -o sub.o   sub.c
gcc -o test main.o sub.o

5. 制作、使用动态库

制作、编译:

# 将main.c预处理、编译、汇编成main.o
gcc -c -o main.o main.c
# 将sub.c预处理、编译、汇编成sub.o
gcc -c -o sub.o sub.c

# 使用sub.o制作动态库 libsub.so,当然可以使用多个.o文件生成动态库
gcc -shared  -o libsub.so  sub.o  sub2.o  sub3.o(可以使用多个.o生成动态库)

# 使用main.o和制作的动态库链接生成可执行程序test,
# 其中-lsub可替换为libsub.so,./lib/是动态库 libsub.so所在的目录,自己指定
gcc -o test main.o  -lsub  -L ./lib/

运行:
方式(1):把 libsub.so 放到Ubuntu的/lib目录,然后就可以运行test程序。
方式(2):如果不想把libsub.so放到/lib,也可以放在某个目录比如 /a,然后在终端执行:

export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/a  
./test

注意:链接时指定的libsub.so目录与运行时指定的libsub.so目录是两码事,两者没有关系。

6. 制作、使用静态库

# 将main.c预处理、编译、汇编成main.o
gcc -c -o main.o  main.c
# 将sub.c预处理、编译、汇编成sub.o
gcc -c -o sub.o   sub.c
# 使用sub.o制作静态库 libsub.a,当然可以使用多个.o文件生成静态库
ar crs libsub.a sub.o sub2.o sub3.o(可以使用多个.o生成静态库)

# 使用main.o和制作的静态库链接生成可执行程序test,
# 如果.a不在当前目录下,需要指定它的绝对或相对路径
gcc -o test main.o libsub.a 

# 指定libsub.a存放的路径
gcc -o test main.o libsub.a -L ../lib/

运行:
不需要把静态库libsub.a放到板子上。

注意:执行arm-linux-gnueabihf-gcc -c -o sub.o sub.c交叉编译需要在最后面加上 -fPIC参数。

7. 很有用的选项

# 查看预处理结果,比如头文件是哪个
gcc -E main.c
# 把所有的宏展开,存在1.txt里
gcc -E -dM main.c  > 1.txt  
# 生成依赖文件abc.dep,后面Makefile会用
gcc -Wp,-MD,abc.dep -c -o main.o main.c
# 它会列出头文件目录、库目录(LIBRARY_PATH)
echo 'main(){}'| gcc -E -v -

8. 使用的程序

hello.c程序如下:

#include <stdio.h>

#define   MAX  20 
#define   MIN  10 

//#define  _DEBUG
#define   SetBit(x)  (1<<x) 

int main(int argc, char* argv[]){
    printf("Hello World \n");
    printf("MAX = %d,MIN = %d,MAX + MIN = %d\n",MAX,MIN,MAX + MIN); 

#ifdef _DEBUG
    printf("SetBit(5) = %d,SetBit(6) = %d\n",SetBit(5),SetBit(6));
    printf("SetBit( SetBit(2) ) = %d\n",SetBit( SetBit(2) ));		
#endif    
	return 0;
}

main.c程序如下:

#include <stdio.h>
#include "sub.h"

int main(int argc, char *argv[]){
       int i;
       printf("Main fun!\n");
       sub_fun();
       return 0;
}

sub.c程序如下:

void sub_fun(void){
       printf("Sub fun!\n");
}

sub.h程序如下:

void sub_fun(void);

注意:
程序中头文件#include <stdio.h>#include "sub.h"的不同:

使用双引号包含的头文件表示程序在当前目录下查找对应的头文件;

使用 <> 包含的头文件表示程序去系统或工具链中指定的目录查找对应的头文件

如果想把#include "sub.h"改为include <sub.h>,则需要把sub.h放到系统或工具链中的目录中。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

怎么使用midjourney?9个步骤教你学会AI创作

人工智能生成艺术作品的时代已经来临&#xff0c;互联网上到处都是试图创造完美提示的用户&#xff0c;以引导人工智能创造出正确的图像——有时甚至是错误的图像。听起来很有趣&#xff1f;Midjourney 是一种更常见的 AI 工具&#xff0c;人们用它只用几句话就能创造出梦幻般的…

【Linux系统编程】15.fcntl、lseek、truncate

目录 fcntl lseek 参数fd 参数offset 参数whence 返回值 应用场景 测试代码1 测试结果 测试代码2 测试结果 查看文件方式 truncate 参数path 参数length 测试代码3 测试结果 fcntl 获取文件属性、修改文件属性。 int flgsfcntl(fd,F_GETFL); //获取 flgs|…

微服务架构是什么?

一、微服务 1、什么是微服务&#xff1f; 微服务架构&#xff08;通常简称为微服务&#xff09;是指开发应用所用的一种架构形式。通过微服务&#xff0c;可将大型应用分解成多个独立的组件&#xff0c;其中每个组件都有各自的责任领域。在处理一个用户请求时&#xff0c;基于…

DOM事件流

DOM事件流 1. 常用事件绑定方式1.1 对象属性绑定1.2 addEventListener()绑定1.3 两种方式区别 2. 事件流2.1 概念2.2 事件顺序2.2.1 捕获阶段2.2.2 目标阶段2.2.3 冒泡阶段 3. 阻止事件冒泡3.1 event.stopPropagation()3.2 stopPropagation与stopImmediatePropagation区别 4. 事…

“科技助力财富增值 京华四季伴您一生”,北银理财深化线下线上客户交流互动

2023年4月12日&#xff0c;北银理财有限责任公司&#xff08;以下简称“北银理财”&#xff09;携手东方财富网启动北银理财财富号&#xff0c;首次采用线上直播及线下主题演讲相结合的方式&#xff0c;在上海举办以“科技助力财富增值&#xff0c;京华四季伴您一生”为主题的机…

6、springboot快速使用

文章目录 1、最佳实践1.1、引入场景依赖1.2、查看自动配置了哪些&#xff08;选做&#xff09;1.3、是否需要修改配置1、修改配置2、自定义加入或者替换组件3、自定义器 XXXXXCustomizer 2、开发小技巧2.1、Lombok1、引入坐标2、在IDEA中安装lombok插件&#xff08;新版默认安装…

趣说数据结构 —— 前言

趣说数据结构 —— 前言 一次偶然的机会&#xff0c;翻到当初自己读大学的时候教材&#xff0c;看着自己当初的勾勾画画&#xff0c;一时感触良多。 很值得一提的是&#xff0c;我在封面后第一页&#xff0c;写着自己的专业和名字的地方下面&#xff0c;写着几行这样的字&…

leetcode刷题(6)

各位朋友们大家好&#xff0c;今天是我的leetcode刷题系列的第六篇。这篇文章将与队列方面的知识相关&#xff0c;因为这些知识用C语言实现较为复杂&#xff0c;所以我们就只使用Java来实现。 文章目录 设计循环队列题目要求用例输入提示做题思路代码实现 用栈实现队列题目要求…

Vue2-黑马(七)

目录&#xff1a; &#xff08;1&#xff09;router-路由嵌套 &#xff08;2&#xff09;router-路由跳转 &#xff08;3&#xff09;router-导航菜单 &#xff08;1&#xff09;router-路由嵌套 我们有这样的需求&#xff0c;我们已经显示了主页&#xff0c;但是主页里面有&…

SpringBoot数据库换源

文章目录 前言一. baomidou提供换源注解 DS二. 手动数据源切换三. AOP自动换源 前言 笔者知道有三种方式: baomidou提供的DS自定义AOP自动换源实现AbstractRoutingDataSource手动换源 一. baomidou提供换源注解 DS 注意 1.不能使用事务&#xff0c;否则数据源不会切换&…

云原生入门

云原生入门. 云原生是一种设计和构建应用程序的方法&#xff0c;它充分利用了云计算的优势&#xff0c;如弹性、可扩展性、自动化和敏捷性。云原生应用程序不仅可以在云中运行&#xff0c;而且是为云而生的&#xff0c;它们采用了一些新式的技术和架构模式&#xff0c;使得应用…

零基础入门python好学么

python对于零基础的小伙伴算是非常友好的了~ python以简单易学著称~ Python简洁&#xff0c;高效的特点&#xff0c;大大提升了程序员的编码速度&#xff0c;极大的提高了程序员的办公效率&#xff0c;比如用其他编程语言5、6行代码才能整明白的&#xff0c;用Python可能1-2行就…

不应使用Excel进行项目资源规划的 7 个原因

项目资源规划早期仅限于基本分配和调度。因此&#xff0c;企业使用自制工具或excel表来执行这一简单功能。然而&#xff0c;随着技术和业务流程的发展&#xff0c;资源规划变得复杂&#xff0c;并包括其他组成部分&#xff0c;如预测和容量规划&#xff0c;优化等。 由于传统…

1.BootstrapTable组件

1.先在页面声明一个表格对象 <table id"table" class"table table-striped"></table> 2.生成表格JS代码如下 var url /log/;var columns [{checkbox: true,visible: true //是否显示复选框},{field: id,title: 序号,width…

若依框架—基于AmazonS3实现OSS对象存储服务

若依框架—基于AmazonS3实现OSS对象存储&#xff0c;其他也适用 文章目录 若依框架—基于AmazonS3实现OSS对象存储&#xff0c;其他也适用上一篇[若依mybatis升级mybatis-plus&#xff0c;其他也适用](https://blog.csdn.net/omnipotent_wang/article/details/128635654?spm10…

MYSQL:查询数据

一、学习目标 了解基本查询语句掌握表单查询的方法掌握如何使用几何函数的查询掌握连接查询的方法掌握如何使用子查询熟悉合并查询结果熟悉如何为表和字段取别名掌握如何使用正则表达式查询掌握数据表的查询操作技巧和方法 二、实验内容 根据不同条件对表进行查询操作&#…

Unity Game FrameWork—模块使用—对象池使用

使用对象池&#xff0c;需继承ObjectBase。首先创建一个OPGame的类&#xff0c;继承于ObjectBase&#xff0c;我们暂且把它叫做OP对象&#xff0c;如下图 OP对象有两个地方可以存储成员对象或变量&#xff0c;一个是在OP对象内部如模型ID&#xff1a;m_ModelID。另一个则是对…

【LeetCode训练营02】两个非空链表相加 详解

目录 题目 解题思路的分享 解题源码的分享 题目 给你两个 非空 的链表&#xff0c;表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的&#xff0c;并且每个节点只能存储 一位 数字。 请你将两个数相加&#xff0c;并以相同形式返回一个表示和的链表。 你可以…

Executor框架简介

Executor系统中&#xff0c;将线程任务提交和任务执行进行了解耦的设计; 线程被一对一映射为服务所在操作系统线程&#xff0c;启动时会创建一个操作系统线程&#xff1b;当该线程终止时&#xff0c;这个操作系统线程也会被回收 Executor框架包含的核心接口和主要的实现类 具体…

Linux下安装Hive

文章目录 1. 确保linux环境下mysql已安装2. 上传安装包3. 解压安装包4. 修改目录名称5. 配置环境变量6. 解压日志jar包冲突7. 拷贝mysql驱动jar包8. 配置hive的参数文件9. 增加hadoop的配置参数10.在mysql中进行相关配置11. 初始化hive的元数据库 1. 确保linux环境下mysql已安装…