Linux 开发工具(vim、gcc/g++、make/Makefile)+【小程序:进度条】-- 详解

目录

  • 一、Linux软件包管理器 - yum(ubuntu用apt代替yum)
    • 1、Linux下安装软件的方式
    • 2、认识 yum
    • 3、查找软件包
    • 4、安装软件
    • 5、如何实现本地机器和云服务器之间的文件互传
  • 二、Linux编辑器 - vim
    • 1、vim 的基本概念
    • 2、vim 下各模式的切换
    • 3、vim 命令模式各命令汇总
    • 4、vim 底行模式各命令汇总
    • 5、vim 中批量添加和删除注释
    • 6、简单 vim 配置
  • 三、Linux编译器 - gcc/g++
    • 1、gcc/g++ 命令 & 程序编译
      • (1)gcc/g++语法
      • (2)预处理(进行宏替换)
      • (3)编译(生成汇编)
      • (4)汇编(生成机器可识别代码)
      • (5)链接(生成可执行文件或库文件)
    • 2、函数库
    • 3、动态链接和静态链接
      • (1)动态链接:链接动态库
      • (2)静态链接:链接静态库
  • 四、项目自动化构建工具 - make/Makefile
    • 1、基本概念
      • (1)背景
      • (2)概念
    • 2、基本使用
      • (1)方式一:直接使用 gcc 命令
      • (2)方式二:可以用 make 命令:
    • 3、原理
      • (1)图解代码
      • (2)make 工作规则
        • (i)依赖文件存在
        • (ii)依赖文件不存在
        • (iii)依赖文件列表为空(特殊)
      • (3) .PHONY关键字
        • (i)无 .PHONY关键字时:
        • (ii)加上.PHONY关键字
    • 4、常用makefile写法
      • (1)内置符号法
      • (2)变量替换法
  • 五、小程序 —— 进度条
    • 1、回车、换行和回车换行
    • 2、行缓冲区概念
    • 3、补充 : 刷新
    • 4、小程序 —— 倒计时
    • 5、进度条代码

一、Linux软件包管理器 - yum(ubuntu用apt代替yum)

本人是乌班图,因此借用他人图

1、Linux下安装软件的方式

在Linux下安装软件的方法大概有以下三种:
1)下载到程序的源代码,自行进行编译,得到可执行程序。
2)获取rpm安装包,通过rpm命令进行安装。(未解决软件的依赖关系)
3)通过yum进行安装软件。(常用)

2、认识 yum

yum是一个在Fedora、RedHat以及CentOS中的前端软件包管理器,能够从指定的服务器自动下载RPM包并且安装,可以自动处理依赖性关系,并且一次安装所有依赖的软件包,无须繁琐地一次次下载、安装。
在这里插入图片描述
注意:一个服务器同一时刻只允许一个yum进行安装,不能在同一时刻同时安装多个软件。

因为yum是从服务器上下载RPM包,所以在下载时必须联网,可以通过ping指令判断当前云服务器是否联网。
在这里插入图片描述

3、查找软件包

[cl@VM-0-15-centos lesson5]$ yum list

使用yum list指令,可以罗列出可供下载的全部软件。
在这里插入图片描述
说明一下:
1)软件包名称:主版本号.次版本号.源程序发行号-软件包的发行号.主机平台.cpu架构。
2)"x86_64"后缀表示64位系统的安装包,"i686"后缀表示32位系统安装包,选择包时要和系统匹配。
3)"el7"表示操作系统发行版的版本,“el7"表示的是"centos7/redhat7”,“el6"表示"centos6/redhat6”。
4)最后一列表示的是“软件源”的名称,类似于“小米应用商店”,“华为应用商店”这样的概念。

这里我们以查找lrzsz为例。

lrzsz可以将Windows当中的文件上传到Linux当中,也可以将Linux当中的文件下载到Windows当中,实现云服务器和本地机器之间进行信息互传。

[cl@VM-0-15-centos lesson5]$ yum list | grep lrzsz

由于包的数量非常多,所以我们可以使用grep指令筛选出我们所关注的包,这里我们以lrzsz为例。
在这里插入图片描述
此时就只会显示与lrzsz相关的软件包。

4、安装软件

指令: sudo yum install 软件名

[cl@VM-0-15-centos yum.repos.d]$ sudo yum install lrzsz

yum会自动找到都有哪些软件包需要下载,这时候敲“y”确认安装,当出现“complete”字样时,说明安装完成。

注意事项:
1)安装软件时由于需要向系统目录中写入内容,一般需要sudo或者切换到root账户下才能完成。
2)yum安装软件只能一个装完了再装另一个,正在使用yum安装一个软件的过程中,如果再尝试用yum安装另外一个软件,yum会报错。

5、如何实现本地机器和云服务器之间的文件互传

既然已经安装了lrzsz,这里就顺便说一下lrzsz如何使用。
指令: rz -E
通过该指令可选择需要从本地机器上传到云服务器的文件。
在这里插入图片描述
指令: sz 文件名
该指令可将云服务器上的文件下载到本地机器的指定文件夹。
在这里插入图片描述
卸载软件
指令: sudo yum remove 软件名

[cl@VM-0-15-centos yum.repos.d]$ sudo yum remove lrzsz

yum会自动卸载该软件,这时候敲“y”确认卸载,当出现“complete”字样时,说明卸载完成。

二、Linux编辑器 - vim

为什么选择使用 vim 呢?

因为 vim 是所有 Linux 环境下自带的。

在这里插入图片描述

1、vim 的基本概念

vim在我们做开发的时候,主要解决我们编写代码的问题,本质上就是一个多模式的文本编辑器。
我们这里主要介绍vim最常用的三种模式:命令模式、插入模式、底行模式

  • 命令模式(Normal mode)
    在命令模式下,我们可以控制屏幕光标的移动,字符、字或行的删除,复制粘贴,剪贴等操作。
  • 插入模式(Insert mode)
    只有在插入模式下才能进行文字输入,该模式是我们使用最频繁的编辑模式。
  • 底行模式(Command mode)
    在底行模式下,我们可以将文件保存或退出,也可以进行查找字符串等操作。在底行模式下我们还可以直接输入vim help-modes查看当前vim的所有模式。

2、vim 下各模式的切换

指令: vim 文件名(记得先创建文件)

root@VM-4-17-ubuntu:~/112/lesson5# vim code.c

进入vim后默认为 命令模式(普通模式),要输入文字需切换到插入模式。
在这里插入图片描述
模式切换指令:
【命令模式】切换至【插入模式】
1)输入「i」:在当前光标处进入插入模式。
2)输入「a」:在当前光标的后一位置进入插入模式。
3)输入「o」:在当前光标处新起一行进入插入模式。

【命令模式】切换至【底行模式】
1)输入「Shift+;」即可,实际上就是输入「:」。

【插入模式】或【底行模式】切换至【命令模式】
1)插入模式或是底行模式切换至命令模式都是直接按一下「Esc」键即可。

3、vim 命令模式各命令汇总

【移动光标】
vim 可以直接用键盘上的方向键来控制光标上下左右移动,但正规的 vim 是用小写英文字母 h、j、k、l 来分别控制光标向左、下、
1)按「k」:光标上移。
2)按「j」:光标下移。
3)按「h」:光标左移。
4)按「l」:光标右移。
在这里插入图片描述

5)按「shift+4 / $」:移动到光标所在行的行尾。
6)按「shift+6 / ^」:移动到光标所在行的行首。
7)按「g+g」:移动到文本开始。
8)按「Shift+g / G」:移动到文本末尾。
9)按「n+Shift+g / G」:移动到第n行行首。
10)按「n+l」:光标移到该行的第 n 个位置,如:5l、56l。
11)按「n+Enter / n+j」:当前光标向下移动n行。
12)按「n+k」:当前光标向下移动n行。
13)按「w」:光标跳到下个字的开头(以单词为单位)。
14)按「e」:光标跳到下个字的字尾(以单词为单位)。
15)按「b」:光标回到上个字的开头(以单词为单位)。

【删除】
1)按「x」:删除光标所在位置的字符。
2)按「n+x」:删除光标所在位置开始往后的n个字符。
3)按「shift+x / X」:删除光标所在位置的前一个字符。
4)按「n+X」:删除光标所在位置的前n个字符。
5)按「d+d」:删除光标所在行。
6)按「n+d+d」:删除光标所在行开始往下的n行。
【复制粘贴】
1)按「y+y」:复制光标所在行到缓冲区。
2)按「n+y+y」:复制光标所在行开始往下的n行到缓冲区。
3)按「y+w」:将光标所在位置开始到字尾的字符复制到缓冲区。
4)按「n+y+w」:将光标所在位置开始往后的n个字复制到缓冲区。
5)按「p」:将已复制的内容在光标的下一行粘贴上。
6)按「n+p」:将已复制的内容在光标的下一行粘贴n次。
7)按「y+y+p」:复制粘贴。
8)按「d+d+p」:复制粘贴。
【剪切】
1)按「d+d」:剪切光标所在行。
2)按「n+d+d」:剪切光标所在行开始往下的n行。
3)按「p」:将已剪切的内容在光标的下一行粘贴上。
4)按「n+p」:将已剪切的内容在光标的下一行粘贴n次。
【撤销】
1)按「u」:如果您误执行一个命令,可以马上按下 u,回到上一个操作。按多次 “u” 可以执行多次恢复。
2)按「Ctrl+r」:撤销 u 操作,也就是撤销的恢复(反撤销)。
【大小写切换】
1)按「~」:完成光标所在位置字符的大小写切换,往后遇到的所有小写字母将被转成大写,所有大写字母将被转成小写。
2)按「n~」:完成光标所在位置开始往后的n个字符的大小写切换。
【替换】
1)按「r」:替换光标所在位置的字符。
2)按「R」:替换光标所到位置的字符,直到按下「Esc」键为止(整体文本替换)。
【更改】
1)按「c+w」:将光标所在位置开始到字尾的字符删除,并进入插入模式。
2)按「c+n+w」:将光标所在位置开始往后的n个字删除,并进入插入模式。
【翻页】
1)按「Ctrl+b」:上翻一页。
2)按「Ctrl+f」:下翻一页。
3)按「Ctrl+u」:上翻半页。
4)按「Ctrl+d」:下翻半页。

4、vim 底行模式各命令汇总

在使用底行模式之前,记住先按「Esc」键确定你已经处于命令模式,再按「:」即可进入底行模式。

【行号设置】
1)「set nu」:显示行号。
2)「set nonu」:取消行号。
【跳到文件中的某一行】
1)「n」:n表示一个数字,在冒号后输入一个数字,再按回车键就会跳到该行了,如输入数字 15 后再回车,就会跳到文章的第 15 行。
【查找字符】
1)「/关键字」:先按 / 键,再输入您想寻找的字符,如果第一次找的关键字不是您想要的,可以一直按 n 会往后寻找到您要的关键字为止。(常用)
2)「?关键字」:先按 ? 键,再输入您想寻找的字符,如果第一次找的关键字不是您想要的,可以一直按 n 会往前寻找到您要的关键字为止。
【批量化替换字符】
1)「%s/printf/cout/g」:把文中所有 printf 替换成 cout(g --global 表示全局的意思)。
【查看函数手册】
1)「!man」: [选项] [函数名](按 q 退出手册)。
【保存退出】
1)「w」:保存文件。
2)「q」:退出vim,如果无法离开vim,可在「q」后面跟一个「!」表示强制退出。
3)「w+q」:保存退出。
【分屏指令】
1)「vs 文件名」:实现多文件的编辑。
2)「Ctrl+w+w」:光标在多屏幕下进行切换。
【执行指令】
1)「!+指令」:在不退出vim的情况下,可以在指令前面加上「!」就可以执行Linux的指令,例如查看目录、编译当前代码等。

5、vim 中批量添加和删除注释

方法一:块选择模式

1)批量添加注释:

  1. 进入 vim 编辑器,按 「ctrl+v 」进入块选择模式(visual block),然后按「j / k」上下移动光标或者「Shift+g / G」移动到末尾等操作选择要添加注释的行。
  2. 再按 「shift+i / I 」(大写字母),进入 Insert 插入模式,输入你要插入的注释符(比如 //)。
  3. 最后按 ESC 键,你所选择的行就被注释上了。

2)批量删除注释:

  1. 同样按 ctrl+v 进入块选择模式,选中要删除的行首的注释符号,注意 // 要选中两个。
    选好之后按 d 键即可删除注释,ESC 保存退出。

方法二:替换命令
在底行模式下,可以采用替换命令进行注释:

1)添加注释:

  1. 「起始行号, 结束行号 s/^/注释符/g」:(表示在 xx 到 xx 行加入注释符,^ 表示行首的意思),然后按下回车键,注释成功。

2)删除注释:

  1. 「起始行号, 结束行号 s/^注释符//g」:(表示取消 xx 到 xx 行行首的注释符),然后按下回车键,取消注释成功。

比如:
在这里插入图片描述
注:如果注释符是 / 则按键里的/用#代替

6、简单 vim 配置

  • 在目录/etc/下面,有个名为vimrc的文件,这是系统中公共的配置文件,对所有用户都有效。
  • 在每个用户的主目录/home/xxx下,都可以自己建立私有的配置文件,命名为“.vimrc”,这是该用户私有的配置文件,仅对该用户有效。例如,root 用户的 /root 目录下,通常已经存在一个 .vimrc 文件,如果不存在,就创建一下。

例如,普通用户在自己的主目录下建立了“.vimrc”文件后,在文件当中输入set nu指令并保存,下一次打开vim的时候就会自动显示行号。

vim的配置比较复杂,某些vim配置还需要使用插件,建议不要自己一个个去配置。比较简单的方法是直接执行以下指令(想在哪个用户下让vim配置生效,就在哪个用户下执行该指令,不推荐直接在root下执行):

curl -sLf https://gitee.com/HGtz2222/VimForCpp/raw/master/install.sh -o ./install.sh && bash ./install.sh

然后按照提示输入root密码:
在这里插入图片描述
在这里插入图片描述
如上图,此指令只适用centos 7,因此借图一用

在这里插入图片描述
配置完成后,像什么自动补全、行号显示以及自动缩进什么的就都有了。

三、Linux编译器 - gcc/g++

1、gcc/g++ 命令 & 程序编译

C/C++ 程序要运行,一般要经历以下步骤:

预处理(进行宏替换)–> 编译(生成汇编)–> 汇编(生成机器可识别代码)–> 链接(生成可执行文件或库文件)

在这里插入图片描述
在这里插入图片描述
Linux 下通过 gcc 命令完成 C 程序编译的过程,通过 g++ 命令完成 C++ 程序编译的过程:

(1)gcc/g++语法

语法: gcc 命令格式:gcc [选项] 要编译的文件 [选项] [目标文件](g++ 与之类似)
常用选项:
1)-E 只进行预处理,这个不生成文件,你需要把他重定向到一个输出文件里面(否则将把预处理后的结果打印到屏幕上)。
2)-S 编译到汇编语言,不进行汇编和链接,即只进行预处理和编译。
3)-c 编译到目标代码
4)-o 将处理结果输出到指定文件,该选项后需紧跟输出文件名。
5)-static 此选项对生成的文件采用静态链接。
6)-g 生成调试信息(若不携带该选项则默认生成release版本)。
7)-shared 此选项将尽量使用动态库,生成文件较小。
8)-w 不生成任何警告信息。
9)Wall 生成所有警告信息。
10)-O0/-O1/-O2/-O3 编译器优化选项的四个级别,-O0表示没有优化,-O1为缺省值,-O3优化级别最高。

(2)预处理(进行宏替换)

预处理阶段会做的事:头文件展开、宏替换、条件编译、去掉注释等等。

预处理指令是以 # 号开头的代码行。

命令格式:gcc –E hello.c –o hello.i

  • 选项 -E,该选项的作用是让 gcc 在预处理结束后停止编译过程。
  • 选项 -o,是指目标文件,.i 文件为已经过预处理的 C 原始程序。

(3)编译(生成汇编)

编译阶段会做的事:语法检查(代码的规范性、是否有语法错误等),函数实例化,生成 .s 汇编文件。

命令格式:gcc –S hello.i –o hello.s
用户可以使用 -S 选项来进行查看,该选项只进行编译而不进行汇编,生成汇编代码。

(4)汇编(生成机器可识别代码)

汇编阶段会做的事:把编译阶段生成的 .s 汇编文件转成 .o 目标文件(二进制机器码)。

命令格式:gcc –c hello.s –o hello.o
用户可使用选项 -c 即可看到汇编代码已转化为 .o 的二进制目标代码。

(5)链接(生成可执行文件或库文件)

在成功编译之后,就进入了链接阶段。

命令格式:gcc hello.o –o hello

2、函数库

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

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

函数库一般分为静态库和动态库两种。

静态库(.a):指编译链接时,把库文件的代码全部加入到可执行文件中,因此生成的文件比较大,但在运行时也就不再需要库文件了。
动态库(.so): 与之相反,在编译链接时并没有把库文件的代码加入到可执行文件中,而是在程序执行时由运行时链接文件加载库,这样可以节省系统的开销。

  • 前面所述的 libc.so.6 就是动态库。gcc 在编译时默认使用动态库。完成了链接之后,gcc 就可以生成可执行文件:gcc hello.o –o hello
  • gcc 默认生成的二进制程序,是动态链接的,这点可以通过 file 命令验证。

3、动态链接和静态链接

生成可执行程序的方式有两种:

(1)动态链接:链接动态库

  • 优点:不需要把相关库中的代码拷贝到可执行程序中,编译效率高,程序运行起来后,需要用到哪个库,再把哪个库加载到内存中,边运行边加载。
  • 缺点:万一有库丢失了,将直接导致程序无法正常运行。

(2)静态链接:链接静态库

  • 优点:不依赖于任何的动态库,自己就可以独立运行
  • 缺点:占磁盘空间,占内存,把相关库中的代码完完全全拷贝到了可执行程序中。

Linux 下生成的可执行程序,默认是动态链接的,如何查看呢?

  • 使用 ldd [filename] 命令可以查看可执行文件的库依赖关系
  • 使用 file [filename] 命令可以查看可执行文件的信息和类型


想要生成的可执行程序是静态链接的,该如何做呢?

gcc -o t_static t.s -static

在这里插入图片描述

四、项目自动化构建工具 - make/Makefile

1、基本概念

(1)背景

  • 对于一个多文件的项目,在 VS 集成开发环境中,可以自动帮我们维护好多文件,我们只需要一键就可以完成对所有文件的编译,生成可执行程序。
  • 而在 Linux,项目的所有文件,都需要我们自己来维护,成本太高,所以要用到 make 和 Makefile 帮我们自动化维护

(2)概念

  • 会不会写 Makefile,从一个侧面说明了一个人是否具备完成大型工程的能力。
  • 一个工程中的源文件不计数,其按类型、功能、模块分别放在若干个目录中,Makefile 定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作。
  • Makefile 带来的好处 —— “自动化编译”,一旦写好,只需要一个 make 命令,整个工程完全自动编译,极大的提高了软件开发的效率。
  • make 是一个命令工具,是一个解释 Makefile 中指令的命令工具,一般来说,大多数的 IDE 都有这个命令,比如:Delphi 的 make,Visual C++ 的 nmake,Linux 下 GNU 的 make。可见,Makefile 都成为了一种在工程方面的编译方法。
  • make 是一条命令,Makefile 是一个文件(文件中保存的是目标文件和原始文件间的依赖关系和依赖方法),两个搭配使用,完成项目自动化构建。

2、基本使用

现在编写了一个 test.c 文件,需要编译文件生成可执行程序:

(1)方式一:直接使用 gcc 命令

 gcc test.c -o test

(2)方式二:可以用 make 命令:

操作如下:

1. 先创建一个简单的C代码如下:
在这里插入图片描述
2. 建一个简单makefile文件,如下
在这里插入图片描述
3. 完成编译工作
在这里插入图片描述
可以看到,只需要一个make命令就能完成编译工作并形成可执行程序。。这就不需要每次编译源文件的时候都输入gcc xxx.c -o xxx这样一长串指令,效率提高了很多!

4. 完成清理工作
在这里插入图片描述
make会根据makefile的内容,完成编译/清理操作。
编译工作仅仅用make一条命令,而清理仅用make clean,是如何实现的?

3、原理

(1)图解代码

在这里插入图片描述

  • 依赖文件列表
  1. 可以同时存在多个源文件,以空格为分隔符,如:test.c test1.c …
  2. 还可以为空,比如下面的清理操作,clean:,这是一种特殊的依赖关系!
  • 依赖关系

目标文件的形成依赖于后面文件列表,这就构成了依赖关系。如上述的 proc:proc.c
,clean: 。(特殊)

  • 依赖方法

目标文件形成的所依赖的方法,也就是光有依赖关系还不够,还得需要对应的方法才能实现。。如上述的gcc以及rm操作就是依赖方法。

此时上述的过程可以这样理解,使用make命令时,会在当前目录下寻找makefile文件,读取里面的内容,并根据依赖关系去找到对应的依赖方法并执行生成对应的目标文件!

(2)make 工作规则

① makefile文件,会被make从上到下开始扫描,默认执行第一对依赖关系和依赖方法,其他的不管,形成的是第一个目标文件!,如下这种情况

(i)依赖文件存在

演示如下:

当前目录下的文件:
在这里插入图片描述
makefile文件内容:
在这里插入图片描述
make一下看结果:在这里插入图片描述
会发现此时执行顺序是从下往上的,不是说仅仅使用make命令时,从上往下读,只会执行第一对依赖关系吗?
是的没错,还是从上往下读,执行第一对依赖关系,但是因为第一对依赖关系中的依赖文件proc.o并不存在于当前目录,那么此时make会在当前文件中找目标文件为proc.o的依赖关系,发现依赖文件proc.s也并不存在,以此类推,最后推导发现依赖文件procc存在,就执行对应的依赖方法,在从下往上。如果推导至最后发现还是没有文件,那么此时的make就会直接退出,并报错!!

②make makefile 在执行gcc命令时候,如果发生了语法错误,就会停止推导过程,如下述两种情况:

(ii)依赖文件不存在

注意:这种情况下的不存在不是文件为空,而是没有创建此文件

演示如下:

当前目录下的文件:
在这里插入图片描述
makefile中的内容:
在这里插入图片描述
code.c文件并不在该目录下,来看结果:
在这里插入图片描述
可见,当依赖文件不存在时,make就不工作了。

(iii)依赖文件列表为空(特殊)

演示如下:

将上述的clean操作放在proc.c前面
在这里插入图片描述
make的结果:
在这里插入图片描述
从上往下读取,但是碰到依赖文件为空时,会直接执行对应的依赖方法,不会再向下推导了。也就是make将这种情况也视为依赖文件存在的情况。。

那么此时如果要执行生成其他的目标文件,那就需要带上对应目标文件的名称!
在这里插入图片描述
所以,我们一般习惯上把形成可执行程序的目标文件放在第一位,文件的清理工作放在其他的位置,这也是开头演示时为什么使用make clean命令的原因!因为文件的清理工作放在其他的位置,不能直接make

小总结: make会自动根据文件的依赖性,进行自动推导,帮助我们执行所有相关的依赖方法!!

(3) .PHONY关键字

.PHONY:xxx(目标文件)
作用:让xxx(目标文件)对应的依赖方法,总是要被执行的!!!!

(i)无 .PHONY关键字时:

在这里插入图片描述

在这里插入图片描述
可以看到,只能make一下,当你连续make多次,是无法实现的! 因为makefile对最新生成的可执行程序,默认不会在重新生成,这样可以提高编译的效率!!除非你更新可执行程序所依赖的源文件时,即更新proc.c的内容才可以重新make!

但是可以加上.PHONY关键字就能打破这种限制!

(ii)加上.PHONY关键字

加上.PHONY关键字就能打破这种限制
在这里插入图片描述
但是实际上对于生成可执行程序的,一般不用这个关键字去修饰,这样编译效率不高(对于一个大工程而言),默认情况都是用于修饰clean这样的项目清理文件。。让清理工作总是被执行!

问题:加上.PHONY关键字是怎么打破这种限制,让文件不需要更新也可以继续make?

我们需要先了解,对于源文件和可执行程序,都是文件,文件=内容+属性(文件的时间+文件的大小…)
首先,用 [stat + 文件] 命令,查到文件对应的时间问题。
在这里插入图片描述
其中Access即当cat 文件的时候就会刷新,但是如果是每次访问一次就刷新的话,系统就一直需要io交互,因此改变了测率,积累一定次数刷新

用 chmod 修改文件的属性
在这里插入图片描述
可以发现属性时间改变了
然后 vim proc.c 修改文件的内容
在这里插入图片描述
我们发现Modify和Change的时间一起改变了,这是因为当对内容做修改时候,可能会引发属性的联动,内容变了,文件的大小可能会变,因此属性也就被修改了

解释完上述内容,我们来看主线任务,proc.c时间在proc前,可以make

在这里插入图片描述
此时已经make过后,如果继续make,则无法编译。

在这里插入图片描述
因此当源文件时间比可执行文件时间新时候,才可以继续编译。
对于上述proc is up to date情况,解决方法一:touch,更新proc.c这个源文件时间,使他在proc之后。
在这里插入图片描述
在这里插入图片描述
当proc.c时间被更新后,也就可以继续编译成proc了
解决方法二:便是我们主线任务的.PHONY
.PHONY的作用就是忽略掉时间对比,既然如此,proc.c与proc也没有谁先谁后之分,因此可以一直编译,即总是被编译
在这里插入图片描述

4、常用makefile写法

原理中的makefile写法依赖方法太多,我们正常的makefile是这样写的。
在这里插入图片描述
简化如下:
在这里插入图片描述
gcc -c 即默认形成同名的.o文件

对于上面的依赖方法的写法还是有点麻烦,还是要写gcc xxx.c -o xxx。(小文件还行)来看以下两种写法。

(1)内置符号法

在这里插入图片描述
% 是makefile语法中的通配符。
%.c :当前目录下所有的.c文件,展开到依赖列表中。
类似于:

	proc1.c proc2.c proc3.c

$< :右侧的依赖文件,一个一个的交给gcc -c选项,形成同名的.o文件
类似于:

	gcc -c proc1.cgcc -c proc2.cgcc -c proc3.c

$^ :所有的依赖文件列表。

$@ :目标文件

执行结果与原先写法相同

注意: 对于清理文件不能用内置符号。

(2)变量替换法

在这里插入图片描述
src后面可以跟多个文件。
这与宏替换类似,以后要是想改文件名,即在上面直接改就好。

使用make指令,默认一次只能生成一个可执行程序。如果如下这么做就可以一次执行多个。
all 依赖 bin1 和 bin2,要形成 all,就要形成 bin1 和 bin2,当 bin1 和 bin2 都形成后,all并没有依赖方法,因此makefile就到这结束了。
在这里插入图片描述
补充:
每次我们在make时,都会有gcc……这条指令显示出来,如果不想显示,可以这样改
在这里插入图片描述
在依赖方法前加上@符号即可。

五、小程序 —— 进度条

gcc/g++,vim,make/makefile — 综合点的案例 – linux第一个偏系统的一个样例程序 进度条

1、回车、换行和回车换行

回车:用 \r 表示。回到当前行的最开始,如果此时写入数据,会依次往后覆盖掉当前行的数据。
换行:用\n表示,表示光标移动到下一行正下方。
回车换行:光标移动到下一行的最开始。

注意:

  • 键盘上的 Enter 键表示:回车并换行。

2、行缓冲区概念

(1)这段代码在 Linux 中运行,会产生什么结果呢?

#include <stdio.h>
#include <unistd.h> //sleep() int main()
{printf("hello world!\n"); //有'\n'sleep(3);return 0;
}

运行结果:先打印出 hello world,然后休眠 5s,结束程序。


(2)这段代码在 Linux 中运行,会产生什么结果呢?

#include <stdio.h>
#include <unistd.h> //sleep()                                                     
int main()
{printf("hello world"); //没有'\n'sleep(5);return 0;
}

运行结果:先休眠了 5s,当 5s 结束后,才打印出 hello world,结束程序。

当 sleep(5); 执行的时候,printf(“hello world”); 已经执行完了,但却没有先打印字符串,这是为什么呢?

printf(“hello world”);已经执行完了,但并不代表字符串就得显示出来。

那在执行 sleep(5); 期间,字符串在哪里呢?

缓冲区(本质就是一段内存空间,可以暂存临时数据,在合适的时候刷新出去)。

在这里插入图片描述

3、补充 : 刷新

刷新是什么?

把数据真正的写入磁盘、文件、显示器、网络等设备或文件中。

刷新策略:

  1. 直接刷新,不缓冲。
  2. 缓冲区写满,再刷新(称为全缓冲)。
  3. 碰到 ‘\n’ 就刷新,称为行刷新。(注:行刷新一般对应的设备是显示器)
  4. 强制刷新。

任何一个 C 程序,启动的时候,都会默认打开三个流(文件):

  • 标准输入 stdin、标准输出 stdout、错误 stderr(类型是 FILE* 文件指针类型)
  • 如果想要让数据在显示器上显示出来,需要向输出流 stdout 中写入数据。

回到前面的问题,为什么在执行 sleep 的时候,没有显示字符串呢?

因为我们想要把字符串显示到显示器上,显示器默认是行刷新,遇到 ‘\n’ 才刷新,而我们前面写的代码中,并没有 ‘\n’,所以 printf 执行完了没有刷新
为了在 printf 执行完的时候,让字符串立马显示出来,需要进行强制刷新,把字符串尽快的写入显示器中。

强制刷新需要用到一个函数:

#include <stdio.h>
int fflush(FILE *stream); //把当前缓冲区的数据写入到流中

因为是让字符串在显示器上显示,所以我们需要传文件指针 File* stdout,代码如下:

#include<stdio.h>
#include<unistd.h> //sleep()                                                     
int main()
{printf("hello world"); //没有'\n',字符串写入到了缓冲区中,但不会被立即刷新出来fflush(stdout);        //强制刷新,把当前缓冲区中的数据写入到输出流文件中sleep(5);return 0;
}

运行结果:先打印出 hello world,然后休眠 5s,结束程序。


4、小程序 —— 倒计时

普通版:换行打印
在这里插入图片描述
在这里插入图片描述
每隔一秒换行打印
在这里插入图片描述

升级版:在一行中打印内容
在这里插入图片描述
运行结果:(借用一下)
在这里插入图片描述
代码中加一个printf(“\r\n”); 就会重启一行表示结束运行。

问题1:
上述代码存在在一个错误,当你想从10开始打印时候,打印结果会是10,90,80…
因为显示器没有类型的概念,显示器只认识一个一个的字符,printf要把整数1234,转化成“1”,“2”,“3”,“4”。
因此我们打印10的时候会打印成“1”+“0”,然后\r回到最开始后,只会覆盖一个数字,“0”不会被覆盖。
在这里插入图片描述
改成左对齐就好。

5、进度条代码

简易版:
在这里插入图片描述
演示如下:
在这里插入图片描述
接下来引入usleep,可以用man usleep 来使睡眠周期以微秒为单位增加
再加上一些美化:
在这里插入图片描述

演示如下:
在这里插入图片描述
再优化一下:
在这里插入图片描述

演示如下:

在这里插入图片描述

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

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

相关文章

WebGL系列教程八(GLSL着色器基础语法)

目录 1 前言2 基本原则3 基本数据类型4 顶点着色器和片元着色器4.1 声明4.2 初始化项目4.3 赋值 5 结构体5.1 声明5.2 赋值 6 函数6.1 基本结构6.2 自定义函数6.3 常用内置函数 7 精度8 其他9 总结 1 前言 通过前七讲&#xff0c;我们已经见过了WebGL中的部分基础语法&#xff…

Java语言程序设计——篇十一(3)

&#x1f33f;&#x1f33f;&#x1f33f;跟随博主脚步&#xff0c;从这里开始→博主主页&#x1f33f;&#x1f33f;&#x1f33f; 欢迎大家&#xff1a;这里是我的学习笔记、总结知识的地方&#xff0c;喜欢的话请三连&#xff0c;有问题可以私信&#x1f333;&#x1f333;&…

Google大数据架构技术栈

数据存储层 Colossus Colossus作为Google下一代GFS&#xff08;Google File System&#xff09;。 GFS本身存在一些不足 单主瓶颈 GFS 依赖单个主节点进行元数据管理&#xff0c;随着数据量和访问请求的增长&#xff0c;出现了可扩展性瓶颈。想象一下&#xff0c;只有一位…

人工智能——猴子摘香蕉问题

一、实验目的 求解猴子摘香蕉问题&#xff0c;根据猴子不同的位置&#xff0c;求解猴子的移动范围&#xff0c;求解对应的过程&#xff0c;针对不同的目标状态进行求解。 二、实验内容 根据场景有猴子、箱子、香蕉&#xff0c;香蕉挂天花板上。定义多种谓词描述位置、状态等…

Git使用详解:从安装到精通

前言 什么是Git Git是一个分布式版本控制工具&#xff0c;主要用于管理开发过程中的源代码文件&#xff08;Java类、xml文件、html页面等&#xff09;&#xff0c;在软件开发过程中被广泛使用。 可以理解&#xff1a; git是一个管理源代码的工具&#xff0c;主要用于企业团队开…

Python编码系列—Python原型模式:深克隆与高效复制的艺术

&#x1f31f;&#x1f31f; 欢迎来到我的技术小筑&#xff0c;一个专为技术探索者打造的交流空间。在这里&#xff0c;我们不仅分享代码的智慧&#xff0c;还探讨技术的深度与广度。无论您是资深开发者还是技术新手&#xff0c;这里都有一片属于您的天空。让我们在知识的海洋中…

通信工程学习:什么是FDMA频分多址

FDMA&#xff1a;频分多址 FDMA&#xff08;Frequency Division Multiple Access&#xff0c;频分多址&#xff09;是一种在无线通信领域广泛应用的多址技术。该技术通过将可用的频谱资源按频率划分&#xff0c;把传输频带划分为若干较窄且互不重叠的子频带&#xff08;或称信道…

【C语言】malloc()函数详解(动态内存开辟函数)

&#x1f984;个人主页:修修修也 &#x1f38f;所属专栏:C语言 ⚙️操作环境:Visual Studio 2022 目录 一.malloc()函数简介 1.函数功能 2.函数参数 &#x1f4cc;size_t size 3.函数返回值 4.函数头文件 5.函数生成空间(与calloc区别) 二.malloc()函数的具体使用 1.使…

STL值list

list容器 头文件&#xff1a;#include<list> - list是一个双向链表容器&#xff0c;可高效地进行插入删除元素 - list不可以随机存取元素&#xff0c;所以不支持at.(pos)函数与[]操作符 注&#xff1a;list使用迭代器访问数据时可以一步一步走自增自减&#xff08;即…

分享一个基于微信小程序的居家养老服务小程序 养老服务预约安卓app uniapp(源码、调试、LW、开题、PPT)

&#x1f495;&#x1f495;作者&#xff1a;计算机源码社 &#x1f495;&#x1f495;个人简介&#xff1a;本人 八年开发经验&#xff0c;擅长Java、Python、PHP、.NET、Node.js、Android、微信小程序、爬虫、大数据、机器学习等&#xff0c;大家有这一块的问题可以一起交流&…

【苍穹外卖】总结

1 pom 依赖 1.1 MyBatis Spring 用于简化 MyBatis 与 Spring Boot 的集成&#xff0c;提供了对 MyBatis 框架的自动配置支持&#xff0c;简化了数据访问层的开发 1.2 Lombok Lombok 是一个 Java 库&#xff0c;能够通过注解自动生成常见的代码&#xff08;如 getter、setter、…

看Threejs好玩示例,学习创新与技术(三)

本文接上篇内容&#xff0c;继续挖掘应用ThreeJS的一些创新算法。 1、获得鼠标移动对应的地理位置 这个算法如果放在几年前&#xff0c;那肯定会难倒一帮人的。因为是三维投影涉及矩阵变换及求逆&#xff0c;而且还是投影模式下的。在Project Texture这个示例中&#xff0c;作…

Apache-wed服务器环境的安装

一。安装httpd并且开启httpd yum install httpd systemctl start httpd 二。关闭防火墙 systemctl stop firewall 三。常规配置wed服务 mkdir /www vim index.html&#xff08;里面写入自己的内容&#xff09; chmod 755 index.htm chmod 755 /www vim /etc/httpd/co…

从冯唐的成事心法 看SAP协助企业战略落地到信息化

冯唐的《成事心法》是一部结合古代智慧和现代管理理念的著作&#xff0c;通过分析和解读古代名臣张居正的管理方法&#xff0c;提出了一套实用的成事之道。这本书的结构循序渐进&#xff0c;讲解了如何在工作和生活中实现目标、解决问题。以下是《成事心法》的主要结构和内容概…

【Node.js】初识微服务

概述 Node.js 的微服务架构是一种通过将应用程序分解为独立的、松耦合的小服务的方式进行系统设计。 每个微服务负责处理一个特定的业务功能&#xff0c;并且这些服务可以独立开发、部署、扩展和管理&#xff0c;并且可以通讯。 它的核心思想就是解耦。 微服务和微前端是类…

FastText 和 Faiss 的初探了解

概览 大模型目前已经是如火如荼的程度&#xff0c;各个大厂都有推出面向大众的基础大模型&#xff0c;同时诸多行业也有在训练专有大模型&#xff0c;而大模型的发展由来却是经过多年从文本检索生成、深度学习、自然语言处理&#xff0c;在Transformer架构出来后&#xff0c;才…

前端基础知识+算法(一)

文章目录 算法二分查找条件注意方式基本原理左闭右闭正向写法 左闭右开正向写法 前端基础知识定时器及清除盒子垂直水平居中的方式垂直水平1.flex布局2.grid布局3.定位对于块级元素 解决高度塌陷的方式1.给父元素一个固定的高度2.给父元素添加属性 overflow: hidden;3.在子元素…

ip映射域名,一般用于mysql和redis的固定映射,方便快捷打包

举个例子 192.168.3.101mysql映射到mysql.smartlink.com 192.168.3.101redis redis.smartlink.com 要将IP地址映射到域名&#xff0c;可以通过几种方式实现&#xff0c;包括修改本地主机文件&#xff08;仅适用于本地开发环境&#xff09;、设置DNS解析&#xff08;适用于生产环…

IDEA-调用Restful接口

告别Swagger3/Apifox/Postman Swagger3&#xff08;丝袜哥&#xff09; 地址&#xff1a;REST API Documentation Tool | Swagger UI简介&#xff1a;在java代码里面增加注解生成接口文档 在代码里面增加注解 RestController RequestMapping("api/v1/user") Api(ta…

Java外卖小程序管理系统

技术架构&#xff1a; springboot ssm mysql redis 有需要该项目的小伙伴可以添加我Q&#xff1a;598748873&#xff0c;备注&#xff1a;CSDN 功能描述&#xff1a; 商品管理&#xff1a;新增商品、所有商品 菜单管理&#xff1a;菜单管理、菜单分类 订单管理&#x…