Linux学习记录——유 gcc/g++基础知识

news2024/11/20 6:32:06

文章目录

  • 一、程序翻译
  • 二、gcc使用
      • 1、-o
      • 2、预处理-E
      • 3、编译-S
      • 4、汇编-c
      • 5、链接
  • 三、库
  • 四、库的部分实际操作
  • 五、Linux项目自动化构建工具 make/Makefile
      • 1、规则


一、程序翻译

C语言中,写出代码后,编译器会经过四个阶段才会生成可执行文件。

预处理(头文件展开,条件编译,宏替换,去注释)

编译(汇编语言)

汇编(汇编->可重定位目标二进制文件,不可以被执行的, bin.obj,只把我们自己的代码进行翻译,形成二进制目标文件)

链接(将形成的obj文件和库文件合并,形成可执行程序)

回顾一下这个后,我们再来看gcc/g++使用。这两个其实都一样,不过一个是C语言的,一个是C++的。本篇就gcc来写。

二、gcc使用

1、-o

对一个.c文件,直接gcc的话,我们知道会形成一个a.out文件。如果想形成自己命名的一个文件,需要用到gcc -o指令

[zyd@ecs-83301 zzz]$ vim test.c
[zyd@ecs-83301 zzz]$ cat test.c
#include <stdio.h>

int main()
{
  printf("hello world\n");
  printf("hello world\n");
  printf("hello world\n");
  printf("hello world\n");
  return 0;
}
[zyd@ecs-83301 zzz]$ ls
test.c
[zyd@ecs-83301 zzz]$ gcc -o myfile test.c
[zyd@ecs-83301 zzz]$ ls
myfile  test.c
[zyd@ecs-83301 zzz]$ 

也有另一种写法

[zyd@ecs-83301 zzz]$ gcc test.c -o myfile1
[zyd@ecs-83301 zzz]$ ls
myfile  myfile1  test.c
[zyd@ecs-83301 zzz]$ 

-o后面跟的是要指定生成的名称

2、预处理-E

预处理(头文件展开,条件编译,宏替换,去注释)

用gcc是把上面四个阶段全部都过去了,如果我只想看预处理阶段的情况呢?我们先改一下test.c文件

  1 #include <stdio.h>
  2 
  3 #define PRINT                                                                                                                                                                                                 
  4 #define PRINT [ID]     
  5 
  6 int main()
  7 {
  8   printf("hello world\n");
  9   printf("hello 1\n");
 10   //printf("hello world\n");
 11   //printf("hello world\n");
 12   printf("hello 2\n");
 13 
 14   printf("M: %d\n", M);
 15 
 16 #ifdef PRINT
 17   printf("hello PRINT\n");
 18 #else
 19   printf("hello print\n");
 20 #endif
 21 
 22   return 0;
 23 }
~
~

这样就包含了注释,条件编译,头文件展开,宏。
保存退出后,若想要看到预处理结果,需要用到-E指令。
-E:从现在开始进行程序的翻译,预处理做完,就停下来

[zyd@ecs-83301 zzz]$ gcc -E test.c -o file1.i

如果不加后面的-o指令,程序就会把预处理后的全部打印到屏幕上。预处理后的文件后缀应是i。

打开预处理后的文件,文件最后是这样

在这里插入图片描述
可以看到注释,宏替换等等都已经做了,条件编译也选择打印PRINT。而前面八百多行则是展开后的头文件。

3、编译-S

编译(汇编语言)

要看编译文件,需要用到-S指令
-S:从现在开始进行程序的翻译,编译做完,就停下来

和-E一样,也可以不同种写法。
在这里插入图片描述
现在我们简单些看
在这里插入图片描述

打开file.s文件,里面的行数就减少了很多,变成了汇编语言

在这里插入图片描述

4、汇编-c

汇编(汇编->可重定位目标二进制文件,不可以被执行的, bin.obj,只把我们自己的代码进行翻译,形成二进制目标文件)

-c:从现在开始进行程序的翻译,汇编做完,就停下来

在这里插入图片描述

这时候打开file.o文件会是一堆乱码,因为是二进制文件。这时候.o文件还是不能执行,即便加上有可执行权限也不行。

5、链接

链接(将形成的obj文件和库文件合并,形成可执行程序)

链接是程序自主帮用户链接,之后就形成可执行文件a.out,也可以自定义名字。这时候直接用gcc即可。

在这里插入图片描述

关于程序是否已经链接,我们也可以看到。

在这里插入图片描述
此时可以看到链接了哪个库。我们重点看中间那个。
为什么我们能在linux下编写和编译C/C++代码?Linux系统已经默认携带了语言级别的头文件和语言对应的库。要写成一种语言的代码,我们不仅需要编译器支持,还需要库支持。Linux下,头文件一般在usr/include的目录里,而链接的库则是上面图片中libc那一行。接下来写一写库的具体信息。

三、库

库本质也是一种文件。

静态库一般以lib开头,.a为后缀,libxxxxx.a。在windows下,静态库文件后缀一般为.lib。

动态库一般以lib开头,.so为后缀,libxxxxx.so。在windows下,动态库文件后缀一般为.dll。

Linux在识别的时候会去掉前缀lib和后缀a,中间剩余的就是Linux识别的库。

不过还没有解决问题,我们仍然不知道静态库这个东西为什么叫静态。我们一点点了解。

在下载安装vs时,vs会帮我们装上语言的头文件和库文件,或者我们选择装哪个语言的时候,vs就会装上头文件和库文件,这里前面写过,没有这些,我们无法执行代码。

之前所学的linux指令,有一部分是C语言写的,ldd /usr/bin/指令就可以查看他们的库文件

在这里插入图片描述

lixc.so.6那一行中,后面的libc.so去掉lib,去掉so后就是c。

现在我们如何看待指令?指令其实就是程序,给这个程序起好名后,我们就可以使用这个指令,指令也可以叫做工具。

了解了这些,我们再看库。

程序员写代码的时候,Linux会连接一个库,用到库里的功能时,程序就会进入库搜索,找到后就返回这个函数的地址,那么代码就能正常运行了,而想要找到库,就需要链接器,也就是程序的链接阶段。在程序员没有写代码的时候,编译器里或者Linux里就已经存在库文件了,而当我们把代码写入内存并执行时,整个过程也就运行起来了。如果库没有了,那么程序也就无法正常运行,因为我们链接不到库了,同时如果这个库所有人都可用,这个库就是一个动态库,也称为共享库。动态库系统里只有一份。

静态库

当你写完一些代码后,链接器将你所需要的库中的代码拷贝到你的程序中,不像动态库,动态库是进库里并返回函数地址,静态库是把需要的代码拷贝了过来。这样即使库没有了,但是我们已经拿到代码了,依然不影响程序。

总结

1、静态库和静态链接:链接的时候,如果是静态链接,就找到静态库,拷贝静态库中的需要的代码到用户的可执行程序中

2、动态库和动态链接:链接的时候,如果是动态链接,就找到动态库,拷贝动态库中的需要的代码的地址到用户的可执行程序中相应的位置。

3、静态链接成功:用户程序可以不依赖任何库而独立运行
4、动态链接成功:用户程序一直依赖动态库,一旦库缺失,程序就异常。

5、静态库可能会比较浪费空间。

6、动态库因为可共享的特性。所以真正的实现都在库中,程序内部只有地址,比较节省空间。

7、Linux默认使用动态库

四、库的部分实际操作

假设我们已经创建了一个文件test.c,编译它,命名为myfile-static,后面的-static则是告诉系统强制使用静态库。

 gcc test.c -o myfile-static -static

ll一下会发现,链接静态库的执行文件比动态库大了相当多,而test.c只是一点代码而已。

ldd myfile-static

file myfile-static

我们可以看到信息已经变成了静态库的

五、Linux项目自动化构建工具 make/Makefile

在写gcc的时候,顺序可能会记错,gcc可能会用错,为了能够更方便编译,编写程序,Linux有个工具,就是make/Makefile。

make是一个命令,Makefile是一个文件。

先创建一个Makefile文件。

在这里插入图片描述

1、规则

Makefile是一个围绕依赖关系和依赖方法构建的一个自动化编译的工具。

依赖关系

进入到Makefile文件里。

头一行写:

 file:test.c  

file是要生成的可执行文件的名字,test.c是源代码文件。这里的关系就是依赖关系,file依赖test.c。

依赖方法

有了依赖,也要有依赖的方式。上一行按下空格后,来到下一行,再按Tab键,再输入

gcc -o file test.c

实际上最终的文件file应当依赖的是.o文件,因为汇编之后才能生成可执行文件;而汇编后的文件又是依赖于编译后的文件.s的,编译又依赖于预处理。细究起来确实如此,不过写的时候直接写依赖于test.c文件即可。

  1 file:test.o
  2     gcc -o file test.o
  3 test.o:test.s
  4     gcc -c -o test.o test.s
  5 test.s:test.i
  6     gcc -S -o test.s test.i
  7 test.i:test.c
  8     gcc -E -o test.i test.c
  9      

在这里插入图片描述

清理代码

上面那一行代码

 file:test.c  

冒号左边是目标文件,右边是依赖文件。在依赖关系中,目标文件对应的依赖文件列表可以为空,依赖文件列表是指依赖文件可以有多个。现在写上clean:,后面列表为空,依然可以执行。在依赖方法里,我们用了gcc指令,其他指令一样也可以使用,所以下一行按Tab键后,用上rm指令,就可以删除文件了。

  4 clean:
  5     rm -f file  

在这里插入图片描述

在外部删除时,要带上clean,再次make就又可以创建一次file文件了。但为什么要带上一个clean?Makefile在执行文件时,会默认从上到下执行第一个依赖方法,所以我们要执行clean后面的指令就需要带上clean,clean也是一个目标文件,虽然后面的列表为空,但程序仍然正常看待它,可以执行后面的指令。file目标文件在第一个,所以可以省略,调用时也可以make file。

一般在写清理时,会这样写:

  4 .PHONY:clean
  5 clean:                                                         
  6     rm -f file

.PHONY是一个关键字,意为总是被执行。file没有总是被执行,所以当你多次make时程序就不会多次生成,并提醒用户已经生成了。

在这里插入图片描述

那我们现在也给file加上关键字:

  1 .PHONY:file                                                    
  2 file:test.c           
  3     gcc -o file test.c
  4             
  5 .PHONY:clean
  6 clean:        
  7     rm -f file

在这里插入图片描述

虽然可以多次执行,但最后文件只有一个。

加上这个关键字后,目标文件其实相当于一个伪目标。

在没加关键字之前,系统会提醒你这是最新的可执行文件了,系统不会再去编译,但是系统如何知道最新?假如我们对test.c做一下改变,然后保存退出,再去make,会发现可以编译了,再make又不能编了。对于系统来说,系统会查看源代码和可执行文件的最新时间,只要可执行文件的最新修改时间晚于源代码,就说明这是最新的文件了,就会提醒一下操作者。

针对这点,我们可以欺骗一下系统,touch一次存在过的文件会刷新它的时间,这样就可以继续编译了。

在这里插入图片描述
在这里插入图片描述

结束。

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

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

相关文章

计算数组中元素的加权平均值 numpy.average()

【小白从小学Python、C、Java】【计算机等级考试500强双证书】【Python-数据分析】计算数组中元素的加权平均值numpy.average()[太阳]选择题对于以下python代码最后输出的结果是?import numpy as npa np.array([1, 2, 3, 4])print("【显示】a")print(a)print("…

如何进行Java 单元测试

什么是单元测试 维基百科中是这样描述的&#xff1a;在计算机编程中&#xff0c;单元测试又称为模块测试&#xff0c;是针对程序模块来进行正确性检验的测试工作。程序单元是应用的最小可测试部件。在过程化编程中&#xff0c;一个单元就是单个程序、函数、过程等&#xff1b;…

架构师课程笔记day04——Nginx

大纲 1.从单体到集群过渡 2.Nginx 2.1什么是nginx 2.2常见服务器 2.3nginx在架构中所处位置 2.4使用率&#xff0c;性能&#xff0c;市场占有率等信息 2.5正反向代理啥意思 正向代理 反向代理 示例 2.6安装步骤 Nginx安装步骤 常用命令等 2.7请求链路 2.8进程模型 通用模型 …

JS面向对象基础(原型链、构造函数、new关键字、寄生组合继承、对象元编程)

这篇文章将简单介绍面向对象的基本概念&#xff0c;以及JS语言是如何支持面向对象这种编程范式的&#xff0c;最后还会讲解一些对象元编程的基础知识。通过阅读这篇文章&#xff0c;你可以了解JS中的原型链机制&#xff0c;new和构造函数的原理、寄生组合继承的实现以及对象元编…

李群李代数学习笔记

前言 因为论文学习的需要&#xff0c;入门了一下李群和李代数&#xff0c;觉得B站的这个视频讲得不错&#xff1a;视频地址为机器人学——李群、李代数快速入门&#xff0c;这里记录一下。 前言引入&#xff1a;一些常见的例子S1S^1S1&#xff1a;单位复数SO(2)SO(2)SO(2)&…

ArcGIS基础实验操作100例--实验64创建统计图符号

本实验专栏参考自汤国安教授《地理信息系统基础实验操作100例》一书 实验平台&#xff1a;ArcGIS 10.6 实验数据&#xff1a;请访问实验1&#xff08;传送门&#xff09; 高级编辑篇--实验64 创建统计图符号 目录 一、实验背景 二、实验数据 三、实验步骤 &#xff08;1&am…

24考研数学复习方法、全年规划

文章目录各个阶段推荐的辅导书和习题1.教材基础&#xff1a;22年9月-23年3月复习“三基”2.强化阶段&#xff1a;23年4月-23年8月3.真题阶段&#xff1a;23年9月-10月4.冲刺模拟阶段&#xff1a;23年11-12月各个阶段推荐的辅导书和习题 阶段(时间)辅导教材习题册1.基础阶段(1-…

Vue初识系列【2】内容升级版

文章目录一 模板语法1.1 文本1.2 原始THTML1.3 属性Attribute1.4 JavaScript表达式的使用二 条件渲染2.1 v−if&v−elsev-if\&v-elsev−if&v−else2.2 v−showv-showv−show2.3 v−ifv-ifv−if与v−showv-showv−show的区别三 列表渲染3.1 v−forv-forv−for列表渲…

OpenSceneGraph几何基础教程【OSG】

默认情况下&#xff0c;OSG 使用顶点数组法和显示列表法来渲染几何体。 但是&#xff0c;渲染策略可能会发生变化&#xff0c;具体取决于几何数据的呈现方式。 在本文中&#xff0c;我们将了解在 OSG 中处理几何体的基本技术。 OpenSceneGraph 后端的 OpenGL 使用几何图元&…

Typora 图床教程(阿里云版)

由于码云现在需要登录才能看到相关图片文件后&#xff0c;导致我们已经不能愉快的使用它作为图床了&#xff0c;所以我们需要使用其他工具来作为图床使用了&#xff0c;本文使用阿里云OSS作为Typora的图床。 阿里云OSS相较于其他几个方法来说最大的优点就是稳定了&#xff0c;…

《图机器学习》-Machine Learning for Graphs

Machine Learning for Graphs一、Application of Graph ML一、Application of Graph ML 图机器学习的任务可以分为四个类型&#xff1a; NodelevelNode\ levelNode level(结点级别)EdgelevelEdge\ levelEdge level(边级别)Community(subgraph)levelCommunity(subgraph)\ level…

【rpm】源码包制作rpm包|修改rpm、重新制作rpm包

目录 前言 安装rpmbuild rpmbuild制作rpm 包 同时生成devel包 修改rpm、重新制作rpm包 RPM 打包 工具 SPEC文件 rpmbuild的目录和Spec宏变量和参数说明 preamble部分 Body 部分 标题宏变量/工作目录 spec文件信息 符号说明 CMake制作rpm包 HelloWorld 更多SPEC…

微信小程序开发——小程序的宿主环境—组件

一.小程序的宿主环境—组件1.小程序中组件的分类小程序中的组件也是由宿主环境提供的&#xff0c;开发者可以基于组件快速搭建出漂亮的页面结构。官方把小程序的组件分为了9大类&#xff0c;分别是&#xff1a;1.视图容器 2.基础内容 3.表单组件 4.导航组件5.媒体组件 6.map 地…

企业寄件管理系统使用教程

专为企业量身打造的寄件管理类平台&#xff0c;也就是企业寄件管理系统。其存在的意义在哪里&#xff1f;又是如何运用的&#xff1f;我们往下看看......讨论它存在的意义在哪里&#xff0c;我们先来看看企业普遍存在的寄件场景痛点&#xff1a;1、最早的手写快递单&#xff0c…

一维差分(例acwing重新排序)

一维差分是为了解决访问一个数组中的几个区间&#xff0c;降低时间复杂度使用的差分就是前缀和的逆运算&#xff08;a[i]b[1]b[2]…b[i]&#xff09;差分的作用就是快速实现将数组部分加上一个数。例如给定一个数组 A 和一些查询 Li,Ri&#xff0c;求数组中第 Li 至第 Ri 个元素…

Maven高级-属性-版本管理-资源配置-多环境开发配置-跳过测试

Maven高级-属性 4.2)属性类别 1.自定义属性 2.内置属性 3.Setting属性 4.Java系统属性 5.环境变量属性 4.3)属性类别&#xff1a;自定义属性 作用 等同于定义变量&#xff0c;方便统一维护 定义格式&#xff1a; <!--定义自定义属性--> <properties><…

STM32MP157驱动开发——Linux ADC驱动

STM32MP157驱动开发——Linux ADC驱动0.前言一、ADC 简介1.ADC 简介2.STM32MP157 ADC简介二、ADC 驱动源码解析1.设备树下的 ADC 节点2.ADC 驱动源码分析1&#xff09;stm32_adc 结构体2&#xff09;stm32_adc_probe 函数3&#xff09;stm32_adc_iio_info 结构体三、驱动开发1.…

【深度学习】经典算法解读及代码复现AlexNet-VGG-GoogLeNet-ResNet(二)

链接: 【深度学习】经典算法解读及代码复现AlexNet-VGG-GoogLeNet-ResNet(一) 4.GoogLeNet 4.1.网络模型 GoogLeNet的名字不是GoogleNet&#xff0c;而是GoogLeNet&#xff0c;这是为了致敬LeNet。GoogLeNet和AlexNet/VGGNet这类依靠加深网络结构的深度的思想不完全一样。Go…

创建Vue3项目以及引入Element-Plus

创建Vue3项目以及引入Element-Plus 前提条件&#xff1a;本地需要有node环境以及安装了npm&#xff0c;最好设置了镜像&#xff0c;这样下载包的时候会快些。 1、安装vue脚手架vue-cli3 npm install vue/cli -g2、安装后查看vue的版本 vue -V3、创建Vue项目&#xff0c;项目…

通信电子、嵌入式类面试题刷题计划01

文章目录001——什么是奈奎斯特采样定理&#xff1f;002——有源滤波器和无源滤波器的区别是什么&#xff1f;003——什么是反馈电路&#xff1f;请举出相关应用004——什么是竞争冒险现象&#xff1f;如何消除和避免此类现象005——什么是基尔霍夫定理&#xff1f;006——if e…