Linux开发工具:gcc和g++

news2024/11/27 22:38:15

目录

一. 什么是gcc和g++

二. gcc的基本使用方法

三. 库和链接

3.1 动态库和静态库

3.2 动态链接和静态链接

四. Debug和Release

五. makefile和make

六. 总结 


一. 什么是gcc和g++

  • gcc:Linux下编译C语言程序的编译器
  • g++:Linux下编译C++代码的编译器

由于C++兼容C语言,因此g++既可以编译C++也可以编译C语言。但是,一般建议使用gcc编译C语言,使用g++编译C++。

gcc和g++的使用方法完全一致,因此,本文以gcc为例讲解gcc/g++的使用方法。

二. gcc的基本使用方法

以mycode.c代码为例,生成可执行文件的一般指令为:

  • gcc mycode.c -std=c99

生成可执行文件的默认文件名为a.out,程序运行的指令为:./a.out

图2.1 使用gcc编译C语言代码

如果我们希望自定义可执行文件的文件名,就需要用到-o选项:

  • -o选项:将生成的文件,输出重定向的特定文件

假设我们希望生成的可执行文件文件名为mytest,那么指令应为:gcc mycode.c -o mytest.txt -std=c99,通过ll指令,可以看到生mytest文件生成成功。

图2.2 使用-o选项自定义可执行文件文件名

我们知道,源文件(.c/.cpp)到可执行程序,需要经过四个步骤(预编译、编译、汇编、链接),每一步完成的工作为:

  1. 预编译(预处理):头文件的包含、注释的删除、宏替换、条件编译,生成.i文件。
  2. 编译:将C/C++代码转换为对应汇编代码,生成,s文件。
  3. 汇编:将汇编代码转换为可识别的机器码(二进制指令)。
  4. 链接:将多个目标文件和链接库进行链接。

由可执行文件生成的四个步骤,引出gcc/g++的三个选项:

  • -E:从当前开始翻译,完成预处理就停止。
  • -S:从当前开始翻译,完成到编译就停止。
  • -c:从当前开始翻译,完成到汇编就停止。

通过指令gcc -E mycode.c -o mycode.i -std=c99,生成预处理后的文件mycode.i,用vim打开两份文件,可以看出所有的条件编译、注释、宏和头文件,均按规则进行了处理(见图2.3)

图2.2 预处理完成后就停止
图2.3 预处理前(右)后(左)的文件内容对比

通过gcc -S mycode.i -o mycode.s -std=c99,生成编译后的文件mycode.s,使用vim打开mycode.s文件,可以看到程序对应的汇编代码。

图2.3 完成编译工作就停止
图2.4 对mycode.i编译生成的汇编代码

通过指令gcc -c mycode.s -o mycode.o -std=c99,生成二进制的目标文件mycode.o,这里由于vim是文本编辑器,查看二进制文件mycode.o看到的会是乱码,可以使用od来查看二进制文件内容,od查看二进制文件指令为:od 二进制文件名

图2.5 完成汇编工作就停止
图2.6 使用od查看二进制文件

如果不使用-o、-i、-s选项中的任意一个,那么直接默认完成到链接工作,生成可执行文件。

可执行程序形成的时候,不是无序的二进制构造,而是遵循自己的格式 -- ELF格式。通过指令:readelf -S 可执行文件名可以查看可执行文件的二进制构成。

图2.7 readelf查看可执行文件的二进制构成

三. 库和链接

3.1 动态库和静态库

链接,就是将汇编之后生成的二进制目标文件,与标准库进行链接。

库,本质上就是源文件(.c/.cpp)经过一定的翻译后进行打包后的文件,库有自己的路径。使用库可以达到隐藏源文件的目的, 库中提供函数方法的具体实现。

可以这样认为:头文件提供方法声明 + 库提供方法实现 + 用户代码 = 软件。

库,可分为动态库和静态库,在Window和Linux系统中,根据后缀名不同来区分动静态库:

  • 在Linux环境下:.so(动态库)、.a(静态库)
  • 在Windows环境下:.dll(动态库)、.lib(静态库)

库有自己的命名规则:libname.so.XXX,libname.a.XXX,其中库的实际名称只有中间name那一小部分,lib为前缀,.so.XXX/.a.XXX为后缀。

在Liunx系统中,库文件默认存储在路径/lib64/下使用指令ls /lib64/libc.so*和ls /lib64/libc.s*,可以分别查看C语言的动态库和静态库。

图3.1 C语言动静态库的查看

Linux系统中,默认只有C/C++的动态库,没有静态库,静态库需要自行安装,安装方法为:

  • C语言静态库:yum install -y glibc-static
  • C++静态库:yum install -y libstdc++-static

3.2 动态链接和静态链接

  • 动态链接,就是在代码执行过程中,通过链接关系,让执行流跳转到库中去执行。
  • 静态链接,就是将库中的方法,拿到源文件调用库中方法的位置,执行流不会跳转到库的内部执行。

如果动态库缺失,那么涉及到动态库的所有程序,都不能正常运行。如果静态库缺失,方法的实现已经被提取到了可执行文件中,程序依旧能正常运行。

动态链接和静态链接各有其优缺点:

  • 动态链接可执行文件小,但如果动态库缺失,可能大范围造成程序不可运行
  • 静态链接静态库缺失不影响程序运行,安全性更高,但是可执行程序的占用空间会大幅膨胀。

在默认情况下,gcc采用动态链接的方式编译源文件,如果希望采用静态链接的方式编译代码,首先要保证静态库存在,然后显示声明选项-static, 即可执行静态链接。

  • gcc mycode.c -o mytest-static - std=c99 -static -- 采用静态链接方式编译mytest.c文件

如图3.2所示,分别采用动态链接和静态链接的方式,编译mycode.c源文件,生成可执行文件mytest和mytest-static,通过ll查看文件属性,看到采用静态链接的可执行文件占用空间明显大于采用动态链接的。

图3.2 采用动态链接和静态链接的方法生成可执行文件

关于查看可执行程序的动静态链接情况,有以下两条指令:

  • file指令:查看可执行文件的动静态链接情况。
  • ldd指令:查看可执行文件动静态链接所依赖的动态库。
图3.3 file和ldd指令查看

关于动静态库是否存在与动静态链接是否能够完成的关系,有下面三条规律:

  1. 如果静态库不存在,那么一定不能完成静态链接。
  2. 如果动态库不存在,静态库存在,gcc不使用-static选项,那么依旧能够生成可执行文件,只不过是以静态链接的方式生成的。
  3. 根据第1和第2条规律,如果gcc不使用-static选项,那么可执行文件可能是动态链接和静态链接并存的。 

四. Debug和Release

Debug为调试版本,以Debug版本发布的可执行程序,会带有调试信息。Release为发布版本,以Release版本发布的可执行程序,不会带有调试信息。Release相比于Debug,运行效率高,运行内存消耗低,占用空间少,整体的性能较优,但是Release版本不能调试。

gcc默认情况采用Release版本发布可执行文件,如果要采用Debug版本发布,那么需要-g选项。

图4.1对比了采用Release版本可Debug版本发布的可执行文件mytest和mytest-debug的占用空间大小,可以看出Debug发布的可执行程序相比于Release占用更多空间。 

图4.1 采用Release和Debug发布可执行程序

五. makefile和make

如果源文件过多,那么手动输入文件名就会十分麻烦,并且如果要删除可执行程序,采用rm批量删除容易误删。通过makefile和make配合使用,可以避免上述问题。

  • makefile:是一个文件。
  • make:是一条指令。

我们需要在源文件的路径下面,通过touch makefile,创建名为makefile的文件。vim makefile打开文件,在首行输入依赖关系,另起一行输入依赖方法(见图5.1),保存并退出makefile文件。我们只需要在命令行中输入指令make,即可生成可执行文件,输入make clean,即可清除可执行文件。

图5.1 makefile文件的内容
图5.2 通过makefile和make实现对源文件的翻译和删除可执行程序

通过指令 read -S mytest-static | grep -i debug,可以筛选出可执行文件中的调试信息。

图5.3 可执行文件调试信息的提取

六. 总结 

  • gcc/g++都是Linux下的代码编译器,gcc只能编译C语言代码,g++既能编译C语言代码也能编译C++代码,因为C++兼容C语言。
  • gcc/g++能够实现从源文件到可执行文件的翻译,有-E/-S/-c选项,功能分别为翻译到 预编译/编译/汇编 就终止翻译,如果不显示声明-E/-S/-c的任意一个,那么直接完成链接操作,生成可执行文件。
  • gcc默认生成的可执行文件的文件名为a.out,如果希望自定义可执行文件文件名,需要-o选项实现,-o的功能为:将生成的文件,输出重定向的特定文件。
  • 库可以分为动态库和静态库,通过后缀名来区分动态库和静态库,库本质上是源文件经过翻译后生成的文件,具有自己的路径,同时,库遵循特定的命名规范。在Linux下,各种库文件存储在路径/lib64/下。
  • 链接分为动态链接和静态链接,动态和静态链接要依赖动态库和静态库。动态链接的可执行文件体积小,但是如果动态库丢失就无法正常运行,安全性相对较低。静态链接的可执行文件体积大,但静态库丢失以及能正常运行。
  • gcc默认采用动态链接的方式生成可执行文件,如要采用静态链接,应使用-static选项。
  • gcc默认采用Release版本生成可执行文件,如果要使用Debug版本,应当使用-g选项。
  • 通过makefile和make、make clean的配合使用,可以快捷实现翻译源文件和删除可执行程序。

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

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

相关文章

Apache网页的优化与安全

文章目录 Apache 网页的压缩Apache的页面缓存Apache页面隐藏版本信息Apache页面设置防盗链 Apache 网页的压缩 检查压缩模块 apachectl -t -D DUMP_MODULES | grep "deflate"安装mod_deflate 模块 如果没有安装mod_deflate 模块,重新编译安装 Apache 添…

嵌入式STM32中时钟系统详细分析

1. STM32的时钟源主要有: 内部时钟 外部时钟 锁相环倍频输出时钟 1.1 详细介绍 HSI(内部高速时钟) 它是RC振荡器,频率可以达到8MHZ,可作为系统时钟和PLL锁相环的输入。 HSE(外部高速时钟) 接入晶振范围是4-16MHZ…

深入理解设计原则之组件构建原则【软件架构设计】

系列文章目录 C高性能优化编程系列 深入理解软件架构设计系列 深入理解设计模式系列 高级C并发线程编程 组件构建原则 系列文章目录1、组件构建原则的定义和解读1、组件2、组件聚合2.1、复用/发布等同原则(REP)2.2 、共同闭包原则(CCP&…

C++(6):函数

函数基础 典型的函数包括:返回类型、函数名字、由 0 个或多个形参组成的列表以及函数体。 通过调用运算符(call operator)来执行函数。 调用运算符的形式是一对圆括号,它作用于一个表达式,该表达式是函数或者指向函数…

1731_makefile编写小结1_编译同目录下的文件

全部学习汇总: GreyZhang/g_makefile: Learn makefile from all kinds of tutorials on the web. Happy hacking and lets find an common way so we may dont need to touch makefile code any more! (github.com) 欢迎路过的YUAN类朋友相互交流,以下是…

每日学术速递6.2

CV - 计算机视觉 | ML - 机器学习 | RL - 强化学习 | NLP 自然语言处理 Subjects: cs.CL 1.BiomedGPT: A Unified and Generalist Biomedical Generative Pre-trained Transformer for Vision, Language, and Multimodal Tasks 标题:BiomedGPT:用于…

chatgpt赋能python:Python反向99乘法表:简单易学的终极练习

Python反向99乘法表:简单易学的终极练习 Python是一门强大而又容易上手的编程语言,而反向99乘法表则是一个极佳的练手项目。不仅能锻炼Python的基本语法和逻辑思维,同时也能体现出代码的风格和美感。本文将以Python反向99乘法表为例&#xf…

基于matlab仿真L形金属块基于时间温度分布图

一、前言 此示例说明了如何使用 Simulink 3D 动画™和 MATLAB 接口来操作复杂对象。 在此示例中,矩阵类型的数据在 MATLAB 和虚拟现实世界之间传输。使用此功能,您可以实现大量的颜色变化或变形。这对于可视化各种物理过程很有用。 我们在L形金属块中使用…

Chain of Thought Prompting和Zero Shot Chain of Thought初步认识

1. 思维链提示(Chain-of-Thought Prompting) 思维链(Chain-of-Thought:CoT)提示过程是一种最近开发的提示方法,它鼓励大语言模型解释其推理过程。下图显示了 few shot standard prompt(左)与链式思维提示过程(右&…

ChatGPT提示词攻略之基本原则

下面是调用openai的completion接口的函数。但在本文中并不是重点。了解一下就好。 import openai import osfrom dotenv import load_dotenv, find_dotenv _ load_dotenv(find_dotenv())openai.api_key os.getenv(OPENAI_API_KEY)def get_completion(prompt, model"gp…

[LeetCode周赛复盘] 第 348场周赛20230604

[LeetCode周赛复盘] 第 348场周赛20230604 一、本周周赛总结6462. 最小化字符串长度1. 题目描述2. 思路分析3. 代码实现 6424. 半有序排列1. 题目描述2. 思路分析3. 代码实现 6472. 查询后矩阵的和1. 题目描述2. 思路分析3. 代码实现 6396. 统计整数数目1. 题目描述2. 思路分析…

10.全局配置 app.json 与页面配置

常用的配置项有 pages 小程序的所有页面window 小程序窗口的外观tabBar 小程序底部的tabBar效果,就是底部的切换那部分style 组件样式版本 目录 1 window 2 tabBar 3 页面配置 1 window 小程序由下面三个部分组成,window可以配置 导航栏区域 与…

JavaSE_day43(多线程单线程区别,图解main方法若是单多线程该如何执行,如何使用多线程2种方式)

1 A.java * 学习多线程之前,我们先要了解几个关于多线程有关的概念。 A:进程:进程指正在运行的程序。确切的来说,当一个程序进入内存运行,即变成一个进程,进程是处于运行过程中的程序,并且具有一定…

【生成数据】绘制简单的折线图

使用scatter绘制散点图并设置其样式 plt.scatter(2, 4, s200)#设置图表标题并给坐标轴加上标签 plt.title("Square Number", fontsize24) plt.xlabel("Value", fontsize14) plt.ylabel("Square of Value", fontsize14)#设置刻度标记的大小 plt.…

2022年,Rust与Go哪一个更好?

这是每一个程序员和开发人员都问过的问题,还有很多人仍然在问,即使他们已经做出了自己的决定。Rust vs. Go。2022年,我应该选择哪一个?或选择哪种语言--Golang或Rust。 Golang和Rust是目前使用的最年轻的编程语言。Go于2009年在谷…

最新ChatGPT4.0Plus开通教程-支付宝购买苹果礼品卡-亲测可用

2023.06.04亲测可用ChatGPT开通Plus教程 前言:一、准备工作二、购买苹果礼品卡一、官网购买礼品卡二、支付宝方式购买 三、AppStore充值礼品卡四、ChatGPT Plus 订阅五、iOS 端 ChatGPT Plus 订阅失败解决方法六、美区AppStore账号ID注册教程: 之前&…

【Svelte】一个简单的前端框架

Svelte.js的学习成本高吗? Svelte是新手编码初学者的完美平台。只需一个HTML/CSS和JavaScript技能组合,您就可以从头开始构建您的第一个网站,而无需额外的知识。 这使得学习曲线非常小,不像它的大多数替代方案。除此之外&#xf…

ChatGLM-6b 多任务微调

ChatGLM-6b也是一种预训练模型,它也可以通过微调来适应下游任务。实验表明,使用ChatGLM-6b微调和Bert类预训练模型微调的效果相近。如果采用多任务设计,ChatGLM-6b的效果会更好。你可以在这里了解更多关于ChatGLM-6B的信息: ChatGLM-6Bhttps:…

边缘化中FEJ图例的理解

如图所示,在解释为什么需要FEJ(First Estimation Jacobian)时,通常会将这个图拿出来说事。但是,很多时候只是一笔带过,这个图看的云里雾里的,不是非常明白(可能是我理解力的问题),所以&#xff…

AngularJs学习笔记--bootstrap

AngularJs学习笔记系列第一篇,希望我可以坚持写下去。本文内容主要来自 AngularJS 文档的内容,但也加入些许自己的理解与尝试结果。 一、总括 本文用于解释Angular初始化的过程,以及如何在你有需要的时候对Angular进行手工初始化。 二、An…