Linux:基础开发工具之Makefile和缓冲区的基本概念

news2024/11/24 15:23:22

文章目录

  • 动静态库
  • 自动化构建代码
  • 缓冲区

动静态库

首先要知道什么是链接:

C程序中,并没有定义printf的函数实现,且在预编译中包含的stdio.h中也只有该函数的声明,而没有定义函数的实现

系统把这些函数实现都被做到名为 libc.so.6 的库文件中去了,在没有特别指定时,gcc 会到
系统默认的搜索路径“/usr/lib”下进行查找,也就是链接到 libc.so.6 库函数中去,这样就能实现函
printf了,而这也就是链接的作用

因此,链接的理解:

  1. 我们实现的代码,很多都是用了别人帮我们写好的函数
  2. 那这些函数是在哪里?如何看到这些函数?就是库的概念

那么动静态库如何理解?有什么区别?

从库的命名来看:
动态库的命名是使用的.so文件的后缀通常是.dll
静态库的命名是使用的.a文件的后缀通常是.lib

那动态库和静态库如何使用,具体是如何作用的?

所谓动态库,就是cc++或其他第三方提供方法的集合,所有的程序用链接的方式关联起来,在库中的所有的函数都有一个入口地址,而动态链接就是把链接的库的函数地址拷贝到可执行程序的特殊位置

静态库和动态库相同,也是一个方法的集合,但是是将所有应用程序以拷贝的方式将需要的代码直接拷贝到可执行程序当中,这样就是静态链接的原理

因此优缺点也就看出来了,动静态库各有利弊:

  1. 对于动态库来说,使用动态链接生成的可执行程序体积很小,比较节约资源,但是从原理上就能看出,动态链接非常依赖动态库,如果动态库被意外损毁,那么整个和这个动态库相关的程序都不能使用了
  2. 对于静态库来说,优点就是可以无视库的概念,可以直接把库内的东西拷贝到本地进行使用,可以进行独立运行,但是缺点也很明显,那就是体积过大,太过于浪费资源,因为要把代码都考取到本地的地方

总结

因此,可以这样进行总结,我们的代码与头文件再加上库就可以被形成可执行程序

所以,所谓的开发环境的安装,其实就是安装下载并拷贝头文件和库文件到开发环境中的特定路径下,让编译器可以找到

所谓开发环境要做到什么才能被称之为开发环境?

  1. 下载开发环境中includelib
  2. 设置合理的查找路径
  3. 规定好形成可执行程序的链接方式

自动化构建代码

在大型文件中会有几百个源文件,那这些文件的编译工作和编译顺序是一个很繁重的事,那么如果有一个工具可以帮助我们进行这些编译的工作,就会节约很大一部分时间,因此就产生了自动化构建代码的工具:make/Makefile

make是一个命令
makefile是一个在当前目录下存在的一个具有特定格式的文本文件

下面开始具体使用makefile:

首先,既然makefile是一个用来进行项目自动化构建的工具,那么首先必须要有可以运行的文件,因此要首先写一个c文件:

在这里插入图片描述

这是一个程序用来倒序输出一段数字,下面要使用makefile工具来进行自动化构建,这个工具的创建十分简单,直接在目录下创建一个Makefile命名的文件即可,接着在这个文件内可以进行一些输入:

mybin:code.c
	gcc code.c -o mybin
.PHONY:clean
clean:
	rm -f mybin

上面是较为基本的版本,一开始的mybin表示最后要生成的文件名字是mybin,而生成mybin需要借助的文件是code.c,对于code.c的操作是用gcc进行编译,这样就可以生成mybin文件,这里要引入两个概念:依赖关系和依赖方法:

何为依赖关系?简单来说,依赖关系就是要完成这个操作需要依赖于什么文件,对于这个文件内的信息来说,依赖关系就是mybin文件的生成需要依赖于code.c这个文件

那何为依赖方法?就是要生成目标文件需要进行什么样的操作,对于这个文件内的信息来说,依赖方法就是要进行gcc code.c -o mybin,这样就能生成mybin,因此这个操作也就被叫做是依赖方法

因此,这样就写好了最初始版本的Makefile文件,这个工具就可以进行一些初步的操作:

在这里插入图片描述
从上面的图中可以看出进行操作的一些步骤,首先当前目录下只有一个code.c和项目自动化构建工具,使用make指令后,就在当前目录下使用gcc编译器完成了编译,生成了mybin文件,此时当前目录下就生成了mybin这个可执行文件,而这个可执行文件运行后的结果也可以被打印出来

下面的操作是make clean,通过这个指令可以调用Makefile文件下的clean指令,可以执行rm命令,将生成的mybin可执行文件进行删除

那现在再次看到Makefile文件,文件内的信息中除了总结的依赖关系和依赖方法外,还有一些没见过的内容,这些内容的意义是什么?

首先是.PHONY:clean,这个语句中有一个.PHONY,这个的意义是作为一个伪目标,那什么又是伪目标?下面进行解释

先说结论,伪目标的意义就是可以让依赖方法总是被执行,不会收到任何情况的阻拦,也就是说如果被确认的伪目标,那么语句总是会被执行的

那问题又来了,什么叫总是被执行,难道还有不会被执行的情况吗?有下面的实验

在这里插入图片描述
上面的实验就很好的说明了这个问题,在这个实验中,第一次使用make指令是可以成功的,可以让code.c经过gcc编译,但是如果继续使用make,就会提示上面的报错信息,而这个报错信息产生的原因其实是因为mybin文件不需要被更新,因此这个自动化构建的工具没有让代码进行编译,也就是说,通过一些比较,是可以让一些代码不再重新编译的,或者总结来说,可以让一些操作不被重复执行,因为执行这些操作没有必要

为什么要这样设置?有什么好处?

为什么Makefilemake不让使用者随时重新编译代码,而是会做出一定的限制?原因在于要提高效率,那么又是如何进行判断的?答案是通过时间进行判断,如果通过时间的判断,Makefile工具发现,mybin实际上不需要重新编译,因为code.c内没有进行任何操作,和之前的编译结果产生是一样的,此时就会不让用户进行编译,这样也能提高效率

那工具是如何做到的?如何进行比较文件的时间,文件的时间又是一个什么样的概念?
因此就引出了文件的ACM时间的概念

想要看到时间需要用到Linux中的一条指令:

stat code.c

在这里插入图片描述
借助这个指令可以看到关于code.c文件的各种信息,其中就包括文件的几个修改时间,下面先看文件的这几个修改时间有什么具体的意义:

首先要清楚前面的一个概念:文件=内容+属性,因此在这里关于文件的修改时间,是包括文件的内容修改时间和文件的属性修改时间

Access时间:Access修改时间指的是文件的内容被查看就会被修改,但Access并非每次被查看都会被记录到这次的时间变化,原因看后续

Modify时间:Modify时间指的是文件的内容被改变的时候,就会改变一次这个时间

Change时间:Change时间指的是文件的属性被修改的时候,就会改变一次这个时间

现在使用vim进入文件中对文件进行一些修改,此时再看文件的各项时间:

在这里插入图片描述

从中可以看出,使用vim对文件进行了一些操作后,时间都被修改了,AccessModify时间被修改是因为文件内容被修改,而文件内容被修改意味着文件的属性也必然会被修改,因此文件的Change时间也被进行了修改,三个时间都进行了一定程度的修改

因此可以从中总结出,Change时间被修改是当文件的属性发生变换时就会修改,因此Change时间是可以单独被修改的,而Modify时间的改变必然会导致其他时间跟着连锁改变,因为文件内容的改变会导致其属性必然改变

回到前面的问题,那这个工具是如何判断什么时候要进行修改?

答案是根据的是Modify的时间来判断,通过Modify的时间就可以对比出来源文件和编译生成的可执行程序的新旧,如果编译出来的可执行程序的时间晚于源文件,就意味着源文件可能被进行了某些修改,需要重新编译,因此此时就具备重新编译的条件,就可以重新编译,但是如果源文件的修改时间晚于可执行程序,就可以被认为源文件在编译形成可执行程序的这段时间内没有进行其他操作,没有重新编译的需要,为了保证效率就不再进行编译,而是直接采用编译好的可执行文件运行即可

Access时间的特殊性

Linux中可以看到的文件,都是在磁盘上进行的存储,而又由于文件是由内容加属性组成的,因此更改时间的本质其实就是访问磁盘

Access时间负责管理的是文件被查看的频率,而如果文件每次被查看都要更改对应的Access时间,那么访问磁盘的频率就过快,而在Linux系统中会存在大量的访问磁盘的IO操作,如果每次查看后都要访问磁盘进行修改时间,会降低系统的效率,因此对于Access时间做了一定的限制,增加了次数限制,因此并不是每次查看文件都会更改这份文件的Access时间

缓冲区

C语言中学习过缓冲区,那时的缓冲区是站在输入输出的角度来看的,现在在Linux中重新认识缓冲区的概念

在c语言中,针对输出流有其特定的默认缓冲区,这里主要研究输出缓冲区,输出缓冲区的位置在哪里?如何证明输出缓冲区的概念?

现在有这样的程序:

#include <stdio.h>
#include <unistd.h>

int main()
{
    printf("hello linux");

    sleep(2);
    return 0;
}

对这个程序编译运行,会发现一个现象:程序会先进行sleep后进行输出打印,按照正常逻辑来看,程序理应是先输出信息再sleep,那么从这个现象中就可以看出,在运行程序的过程中,输出缓冲区确实是存在的,而要输出的信息就存储在输出缓冲区中,还没有被打印到屏幕上,因此会先sleep后再进行显示到屏幕

那么如何处理缓冲区?可以用到缓冲区对应的函数

fflush函数

#include <stdio.h>
#include <unistd.h>

int main()
{
    printf("hello linux");
    fflush(stdout);
    sleep(2);
    return 0;
}

或者也可以直接输出后打上\n,原因是回车换行也是一种刷新的策略

有了上面的基础知识,回顾c语言:

\r = 回车键
\n= 换行键

而键盘中的enter键,实际上就是回车+换行

因此基于上面的原理,可以实现一个有趣的代码

#include <stdio.h>
#include <unistd.h>

int main()
{
    int a=5;
    while(a--)
    {
        printf("%d\r",a);
        sleep(1);
    }
    return 0;
}

上面代码输出的结果是没有结果,原因在于:每当打印一个数字的时候,这个数字一直在缓冲区中,而\r直接把数据进行了覆盖

如果将代码更新为这样:

#include <stdio.h>
#include <unistd.h>

int main()
{
    int a=5;
    while(a--)
    {
        printf("%d\r",a);
        fflush(stdout);
        sleep(1);
    }
    return 0;
}

对于缓冲区的理解

首先要清楚,缓冲区的本质是一个数组,因此对于单句的printf函数,如果用这个语句来看的话,缓冲区中会存储的是a的值和\r,假定这里没有fflush函数也没有sleep函数,那么printf函数就会把所有数据缓存到缓冲区,当程序结束后以此进行打印,把数据和\r看成一组,每执行完数据和\r后光标就回到了最开始的地方

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

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

相关文章

旋转偏心裁切刀切向跟踪及半径补偿

1 裁刀半径补偿问题的提出 偏心裁刀一般皮革和纸箱行业用的比较多&#xff0c;它适用于裁切比较厚的材料。对于如图1所示的偏心裁刀&#xff0c;它的刀尖和旋转轴(也就是刀心)存在一个距离&#xff0c;设为半径r。由于改刀刀刃有方向&#xff0c;所以用该刀去切割直线时&#…

使用nvm管理node.js

使用nvm管理node.js 一、简介 nvm是一个node的版本管理工具。可以在多种系统上管理Node.js 版本的工具。使用 NVM&#xff0c;可以轻松地切换不同版本的Node.js&#xff0c;并方便地管理不同版本的全局包和本地包。 二、安装与下载 1.删除原有node.js 首先需要卸载已安装的…

免费音乐下载网站分享(MP3文件格式)

免费音乐下载网站分享&#xff08;MP3文件格式&#xff09; 最近需要下载一些歌曲&#xff0c;发现很多音乐app上下载文件都需要vip&#xff0c;再上网查询了一番&#xff0c;最后发现了一个宝藏网站&#xff0c;可以免费下载各种格式的MP3文件&#xff0c;在这里给大家分享一…

建设数字孪生智慧城市是未来城市的重要增长点

中国国家创新与发展战略研究会学术委员会常务副主席、重庆市原市长黄奇帆在《瞭望》撰文指出&#xff1a; AI时代的城市是由实体空间和数字空间组成的数字孪生城市&#xff0c;要充分重视对数字空间的治理。随着城市数字化进程的加快&#xff0c;城市、企业、个人开始形成多样化…

软件需求怎么写?

前言&#xff1a;一般来说&#xff0c;软件产品的需求人员的主要输出物就是软件需求&#xff0c;如果这个软件产品就XX系统&#xff0c;人们口中的“系统需求”和“软件需求”就没有什么区别了。在车企行业&#xff0c;推行这ASPICE体系&#xff0c;在这个体系中明确申请了系统…

2023工博会,正运动开放式激光振镜运动控制器应用预览(三)

展会倒计时&#xff1a;4天 本次的中国国际工业博览会正运动技术将携开放式激光振镜运动控制器ZMC408SCAN-V2亮相。 •绿色生产&#xff0c;减少材料和资源浪费&#xff0c;提升可持续性&#xff1b; •节省多套硬件成本&#xff0c;替代传统的激光加工系统&#xff0c;降低项…

【深度学习】树莓派Zero w深度学习模型Python推理

在机器学习开发过程中&#xff0c;当模型训练好后&#xff0c;接下来就要进行模型推理了&#xff0c;根据部署环境可分为三类场景&#xff1a; 边缘计算&#xff1a;一般指手机&#xff0c;嵌入式设备&#xff0c;直接在数据生成的设备上进行推理&#xff0c;因为能避免将采集…

MAC MINI 2012安装Montery折腾笔记

MAC MINI 2012安装Montery折腾笔记&#xff08;作为电视盒子/远程开发机&#xff09; 起因&#xff1a; 手头有个mac mini&#xff0c;2018年买的2手。一直都是10.12系统&#xff0c;处理python和苹果开发都受制于旧系统&#xff0c;很多软件也装不上&#xff0c;于是有了升级…

Qt开发 入门

1.Qt概述 什么是Qt 不论我们学习什么样的知识点首先第一步都需要搞明白它是什么&#xff0c;这样才能明确当前学习的方向是否正确&#xff0c;下面给大家介绍一下什么是Qt。 Qt是一个跨平台的C应用程序开发框架 具有短平快的优秀特质: 投资少、周期短、见效快、效益高几乎支持…

Java-集合类

集合 Java集合是Java中用于存储和管理一组对象的工具。Java集合提供了相应的方法&#xff0c;用于用户对集合内数据的操作。 Java集合类提供了许多不同的数据结构&#xff0c;如列表、队列、栈、集合和映射&#xff0c;以满足不同类型的编程需求。 程序中如何存储大批量同类型…

vue项目中使用特殊字体的步骤

写在前面 在项目中使用特殊字体&#xff0c;需要注意&#xff0c;所使用的特殊字体是否被允许商用或是个人开发&#xff0c;以及如何使用&#xff0c;切记不要侵权。 首先需要在对应字体网站下载字体文件&#xff0c;取出里面后缀名为.ttf的文件 然后把该文件放到src -> ass…

python自(2)切片 字典 遍历删除添加修改查询定义函数函数返回值作用域序列化异常报错urllib使用一个类型六个方法下载 视频音频图片

切片 # # 切片# s hello word# # 下标索引为0的 # print(s[0]) #h# # 左闭右开 &#xff08;左是下标开始的&#xff0c;右是几个索引值&#xff09;例如从0开始算 4个索引值 # print(s[0:4]) #hell# # 更改起始值的开始位置 # print(s[1:]) #ello word# # 下标结束位置 # p…

生成式人工智能在高等教育 IT 中的作用

作者&#xff1a;Jared Pane 通过将你大学的数据与公共 LLMs 和 Elasticsearch 安全集成来找到你需要的答案。 根据 2023 年 4 月 EDUCAUSE 的一项调查&#xff0c;83% 的受访者表示&#xff0c;生成式人工智能将在未来三到五年内深刻改变高等教育。 学术界很快就询问和想象生…

9月14日作业

实现myVector #include <iostream>using namespace std;template <typename T> class myVector { private:T* data;int size;int capacity; public:// 构造函数myVector() : data(nullptr), size(0), capacity(0) {}//拷贝构造函数myVector(const myVector& o…

Jetson Xavier NX开发板无屏幕远程连接

设备&#xff1a; jetson nx &#xff08;ubuntu20.04&#xff09;,win10 目标&#xff1a;实现jetson nx不连接屏幕实现远程连接并控制 网上比较多的答案都是使用vnc,但本人亲尝试过了vnc只有在jetson nx开发板连接有屏幕时候才有空&#xff0c;一旦不连接屏幕&#xff0c;…

千兆以太网网络层 ARP 协议的原理与 FPGA 实现

文章目录 前言一、ARP 帧的应用场景和存在目的二、ARP 帧工作原理三、以太网 ARP 帧发包实例设计四、以太网 CRC校验代码五、以太网 ARP 帧发包测试---GMII1.模拟数据发送2.仿真模块3.仿真波形六、以太网 ARP 帧发包测试---RGMII1.顶层文件2 .仿真代码七、上板测试(RGMII)前言…

浅显易懂理解傅里叶变换

说起电子硬件专业&#xff0c;那不得不提的就是傅里叶变换了。 大学课程中应该吓倒了很多人&#xff0c;谈傅里叶色变了。 本次就来重新认识一下电子硬件中的傅里叶变化。 首先理解之前&#xff0c;当然是需要先知道傅里叶这位大牛的人物百科啦。 傅里叶是法国数学家&#xff0…

【数据结构】平衡二叉搜索树(AVL树)——AVL树的概念和介绍、AVL树的简单实现、AVL树的增删查改

文章目录 平衡二叉搜索树&#xff08;AVL树&#xff09;1.AVL树的概念和介绍2.AVL树的简单实现2.1AVL树的插入2.2AVL树的旋转2.2.1左旋2.2.2右旋2.2.3右左双旋2.2.4左右双旋 全部源码 平衡二叉搜索树&#xff08;AVL树&#xff09; 为什么要引入平衡二叉搜索树&#xff1f; 在之…

jdk 中的 keytool 的使用,以及提取 jks 文件中的公钥和私钥

这里暂时只需要知道如何使用就可以了。 首先是生成一个密钥&#xff0c; keytool -genkeypair -alias fanyfull -keypass ffkp123456 -validity 365 -storepass ffsp123456 -keystore fanyfull.jks -keyalg RSA解释一下这里的选项&#xff0c; -alias 密钥对的名称-keypass …

等变性的AI:从离散到连续

这篇文章主要介绍了在科学问题中如何实现不变性或等变性&#xff0c;其中介绍了实现等变性的数学和物理基础&#xff0c;包括离散和连续对称变换的示例&#xff0c;并描述了在实践中如何使用张量积。文章还讨论了如何处理数据中的对称性&#xff0c;以及如何开发适应对称性约束…