【Linux】-- 开发工具(vim、gcc、g++、make/Makefile)

目录

Linux编辑器-vim使用

vim的基本概念

vim的简单配置

vim的基本操作

vim进阶命令集

插入模式

从插入模式切换为命令模式

移动光标

删除文字

复制

替换

撤销上一次操作

更改

跳至指定的行

vim底行模式命令集

列出行号

跳到文件中的某一行

查找字符

保存文件

离开vim

vim简易命令集 - 最基础的必须会

命令模式的常见命令

底行模式的常见命令

Linux编译器-gcc/g++使用 

背景知识

链接 - 静态库与动态库

动态库 - 动态链接

静态库 - 静态链接

动态链接 - 静态链接

总结

gcc选项

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

make和Makefile

背景

实例代码

伪目标

Linux第一个小程序 - 进度条

\r&&\n

\r

\n

进度条代码


Linux编辑器-vim使用

(编辑器 —— 只能写代码 —— 只能写代码)只关心如何然我们更快更高效的写出代码

        vi/vim的区别简单点来说,它们都是多模式编辑器,不同的是vimvi的升级版本,它不仅兼容vi的所有指令,而且还有一些新的特性在里面。例如语法加亮,可视化操作不仅可以在终端运行,也可以运行于x window mac os、windows。

vim的基本概念

普通 / 命令模式是默认的进入vim的模式。

      此处只有vim的三种模式(实际上有很多模式,但是基础掌握这3种即可),分别是命令模式(command mode)、插入模式(Insert mode)和底行模式(last line mode),各模式的功能区分如下:

  • 正常/普通/命令模式(Normal mode)
    • 控制屏幕光标的移动,字符、字或行的删除,移动复制某区段及进入插入模式下,或者到底行模式
  • 插入模式(Insert mode)
    • 只有在插入模式下,才可以做文字输入,按「ESC」键可回到命令行模式。该模式是我们后面用的最频繁的编辑模式。
  • 末行模式(last line mode)
    • 文件保存或退出,也可以进行文件替换,找字符串,列出行号等操作。 在命令模式下,shift+: 即可进入该模式。要查看你的所有模式:打开vim,底行模式直接输入。

vim的简单配置

        vim的配置比较复杂,某些vim配置还需要使用插件,建议不要自己一个个去配置。建议在网上搜索,找一个自己喜欢的配置进行安装,想在哪个用户下让vim配置生效,就在哪个用户下执行该指令。

        在配置之前,是几乎什么都没有的,而配置完成后,绝大多数,自动补全、行号显示、自动缩进等才会有。

自己调的:

  • 设置语法高亮: syntax on
  • 显示行号: set nu
  • 设置缩进的空格数为4: set shiftwidth=4

【配置文件的位置】

  • 在目录 /etc/ 下面,有个名为vimrc的文件,这是系统中公共的vim配置文件,对所有用户都有效。
  • 而在每个用户的主目录下,都可以自己建立私有的配置文件,命名为:“.vimrc”。例如,/root目录下,通常已经存在一个 .vimrc 文件,如果不存在,则创建之。
  • 切换用户成为自己执行 su ,进入自己的主工作目录,执行 cd ~。
  • 打开自己目录下的 .vimrc 文件,执行 vim .vimrc

想在哪个普通用户下配置vim,就在哪个普通用户下执行该指令,不推荐直接在root下执行:(配置只针对配置的用户自身)

(注意:这个配置包只支持Centos 7)


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

vim的基本操作

  • 进入vim

    在系统提示符号输入vim及文件名称后,就进入vim全屏幕编辑画面:
    • 不过有一点要特别注意,就是你进入vim之后,是处于[正常模式],你要切换到[插入模式]才能够输入文字。
    • vim test.c(使用vim打开test.c文件)
  • [正常模式]切换至[插入模式]

    • 输入a
    • 输入i
    • 输入o
  • [插入模式]切换至[正常模式]

    • 目前处于[插入模式],就只能一直输入文字,如果发现输错了字,想用光标键往回移动,将该字删除,可以先按一下「ESC」键转到[正常模式]再删除文字。当然,也可以直接删除。
  • [正常模式]切换至[末行模式]

    • 「shift + ;」, 其实就是输入「:」
  • 退出vim及保存文件在[正常模式]下,按一下「:」冒号键进入底行模式,例如:
    • : w (保存当前文件)
    • : q! (输入q!,不存盘强制退出vim)
    • : wq (输入「wq」,存盘并退出vim)

vim进阶命令集

  • 插入模式

    • 按「i」切换进入插入模式「insert mode」,按“i”进入插入模式后是从光标当前位置开始输入文件;
    • 按「a」进入插入模式后,是从目前光标所在位置的下一个位置开始输入文字;
    • 按「o」进入插入模式后,是插入新的一行,从行首开始输入文字。
  • 从插入模式切换为命令模式

    •  按「ESC」键。
  • 移动光标

    • vim可以直接用键盘上的光标来上下左右移动,但正规的vim是用小写英文字母「h」、「j」、「k」、「l」,分别控制光标左、下、上、右移一格 

  • 按「G」:移动到文章的最后
  • 按「 $ 」:移动到光标所在行的“行尾”
  • 按「^」:移动到光标所在行的“行首”
  • 按「w」:光标跳到下个字的开头
  • 按「e」:光标跳到下个字的字尾
  • 按「b」:光标回到上个字的开头
  • 按「#l」:光标移到该行的第#个位置,如:5l,56l
  • 按[gg]:进入到文本开始
  • 按[shift+g]:进入文本末端
  • 按「ctrl」+「b」:屏幕往“后”移动一页
  • 按「ctrl」+「f」:屏幕往“前”移动一页
  • 按「ctrl」+「u」:屏幕往“后”移动半页
  • 按「ctrl」+「d」:屏幕往“前”移动半页  
  • 删除文字

    • 「x」:每按一次,删除光标所在位置的一个字符
    • 「#x」:例如,「6x」表示删除光标所在位置的“后面(包含自己在内)”6个字符
    • 「X」:大写的X,每按一次,删除光标所在位置的“前面”一个字符
    • 「#X」:例如,「20X」表示删除光标所在位置的“前面”20个字符
    • 「dd」:删除光标所在行
    • 「#dd」:从光标所在行开始删除#行
  • 复制

    • 「yw」:将光标所在之处到字尾的字符复制到缓冲区中。
    • 「#yw」:复制#个字到缓冲区
    • 「yy」:复制光标所在行到缓冲区。
    • 「#yy」:例如,「6yy」表示拷贝从光标所在的该行“往下数”6行文字。
    • 「p」:将缓冲区内的字符贴到光标所在位置。注意:所有与“y”有关的复制命令都必须与“p”配合才能完成复制与粘贴功能。
  • 替换

    • 「r」:替换光标所在处的字符。
    • 「R」:替换光标所到之处的字符,直到按下「ESC」键为止。
  • 撤销上一次操作

    • 「u」:如果您误执行一个命令,可以马上按下「u」,回到上一个操作。按多次“u”可以执行多次回复。
    • 「ctrl + r」: 撤销的恢复
  • 更改

    • 「cw」:更改光标所在处的字到字尾处
    • 「c#w」:例如,「c3w」表示更改3个字
  • 跳至指定的行

    • 「ctrl」+「g」列出光标所在行的行号。
    • 「#G」:例如,「15G」,表示移动光标至文章的第15行行首

vim底行模式命令集

        在使用末行模式之前,请记住先按「ESC」键确定您已经处于正常模式,再按「:」冒号即可进入末行模式。

  • 列出行号

    • 「set nu」: 输入「set nu」后,会在文件中的每一行前面列出行号。
  • 跳到文件中的某一行

    • 「#」:「#」号表示一个数字,在冒号后输入一个数字,再按回车键就会跳到该行了,如输入数字15,再回车,就会跳到文章的第15行。
  • 查找字符

    • 「/关键字」: 先按「/」键,再输入您想寻找的字符,如果第一次找的关键字不是您想要的,可以一直按「n」会往后寻找到您要的关键字为止。
    • 「?关键字」:先按「?」键,再输入您想寻找的字符,如果第一次找的关键字不是您想要的,可以一直按「n」会往前寻找到您要的关键字为止。
    • 问题:/ 和 ?查找有和区别?操作实验一下
  • 保存文件

    • 「w」: 在冒号输入字母「w」就可以将文件保存起来
  • 离开vim

    • 「q」:按「q」就是退出,如果无法离开vim,可以在「q」后跟一个「!」强制离开vim。
    • 「wq」:一般建议离开时,搭配「w」一起使用,这样在退出的时候还可以保存文件。

vim简易命令集 - 最基础的必须会

命令模式的常见命令

(n代表具体的数字)

  1. yy:将当前光标所在的行复制,可nyy(如:3yy)
  2. p:将复制行进行粘贴,可np(如:2p)
  3. dd:将当前光标所在的行剪切(删除),可ndd(如:4dd)
  4. u:撤销操作
  5. ctrl + r:撤销u操作
  6. shift + g:光标定位到文件的结局
  7. gg:光标定位到文件的开始
  8. n + shift + g:光标定位到文件的任意行G
  9. shift + 6(^):将光标定位到当前行的最开始
  10. shift + 4($):将光标定位到当前行的最结尾
  11. w, b:以单词为单位进行光标的前后移动
  12. h, j, k, l:左,下,上,右
  13. shift + ~:大小写切换
  14. shift + r:进入替换模式
  15. r:替换光标所在的字符,可nr
  16. x 或 X(shift + x):删除光标所在的字符,包含之前或者之后,可nx 或 nX

底行模式的常见命令

(后跟一个「!」表强制)

  1. set no/nonu:打开行号,或者取消行号
  2. vs 文件名:横向分屏操作
  3. sp 文件名:纵向分屏操作
  4. w:写入,w
  5. q:退出,q
  6. :!cmd:不退出vim执行对应的命令(执行命令行,编译,运行,查看man)等

(查看man的用法) 

补充:

在文件之间(分屏操作)切换(命令行模式下)

  1. Ctrl+6一个分屏窗口中切换下一个文件。
  2. bn :下一个文件。
  3. bp : 上一个文件。
  4. Ctrl+ww依次向后切换到下一个分屏窗口中。
  5. f 或 Ctrl+g显示当前分屏窗口中正在编辑的文件名称。

文件改名(底行模式下)

  1. f 新名改变当前分屏窗口中编辑中的文件的名字。

补充:

注释代码(命令行模式下)

  1. 移动光标到要注释的起始行的行首。
  2. 进入命令行后,Ctrl + q 进入可视块模式
  3. 移动光标选中要注释的代码行,利用h, j, k, l:左,下,上,右选择需要注释的。
  4. Shift + i 进入插入模式,键入当前语言的注释符:双斜杠(需要注意的是这时只有首行输入了注释符号)。
  5. Esc键后,你之前选中的代码行会全部加上了注释符。

解注释代码(命令行模式下)

  1. 命令行模式,按ctrl + v进入可视块模式,按小写字母i。
  2. 利用h, j, k, l:左,下,上,右选择需要解注释的。
  3. d键就可全部取消注释。

补充:

全选操作(命令行模式下)

  • 全部删除:gg,然后dG
  • 全部复制:gg,然后ggyG

注意:

        此处的全部复制只是在vim中,于yy运用同理。

补充:

格式化代码(命令行模式下)

  1. gg 跳转到第一行,光标定位到文件的开始。
  2. shift+v 转到可视模式。
  3. shift+g 全选。
  4.  = 格式化代码。

简易(命令行模式下)

        gg=shift+g - 超级好用。

补充:

句子的移动(命令行模式下)

  1. ( 前移1句。
  2. ) 后移1句。
  3. { 前移1段。
  4. } 后移1段。

屏幕的移动(命令行模式下)

  1. Ctrl + u光标向上移动半个屏幕。
  2. Ctrl + d光标向下移动半个屏幕。
  3. Ctrl + b光标向上移动整个屏幕。
  4. Ctrl + f光标向下移动整个屏幕。

补充:
复制一个单词(命令行模式下)

  1. 光标移到想要被复制词的词首,输入yw
  2. 光标移到想到粘贴的位置,输入p

复制几个字母 / 字符(命令行模式下)

  1. 光标移到想要被复制字符的首位置,若想复制n个字符输入:nyl
  2. 光标移到想到粘贴的位置,输入p

补充:

vim打开多文件

  1.  vim 1.txt 2.txt 3.txt 用于一个窗口打开。
  2.  vim -o 1.txt 2.txt 3.txt 用对应的窗口数打开对应文件,以行的方式排列窗口。
  3.  vim -O 1.txt 2.txt 3.txt 用对应的窗口数打开对应文件,以列的方式排列窗口。

补充:

不终止vim使用shell

  1.  Ctrl-z 将当前的 Vi/Vim 进程放到后台执行,之后使用 shell 环境执行命令。
  2.  fg 将位于后台的 Vim 进程放到前台执行,即可再次使用Vim操作界面并恢复到原先的编辑状态。

#问:​​​​​​​Vi编辑器中,怎样将字符AAA全部替换成yyy?

        s/AAA/yyy/g

        在 Vim 中,替换模式可以使用 :s 命令来实现。该命令的语法如下:

:[range]s[ubstitute]/{pattern}/{string}/[flags]

其中:

  • [range]:表示要进行替换操作的行范围,默认为当前行。
  • {pattern}:表示要查找的模式,可以是正则表达式。
  • {string}:表示要替换成的字符串。
  • [flags]:是可选参数,用于指定替换时的一些选项。

        例如,要将当前行中所有的 "foo" 替换成 "bar",可以使用以下命令:

:s/foo/bar/g

        其中 s 表示进行替换操作,g 表示全局匹配(即将每一行中所有匹配到的 "foo" 都替换为 "bar")。如果要对整个文件进行替换操作,则需要在命令前加上 % 符号:

:%s/foo/bar/g

        这样就会将文件中所有匹配到的 "foo" 都替换成 "bar"。除了全局匹配外,还有一些其他可用的标志。例如:

  • c:每次替换前都会询问用户是否确认。
  • i:忽略大小写进行匹配。
  • n:不执行实际的替换操作,只显示匹配到的结果。
  • &:重复上一次的替换操作。

        例如,要对整个文件进行不区分大小写的替换操作,并在每次替换前询问用户是否确认,可以使用以下命令:

:%s/foo/bar/gic

        这样就会将文件中所有匹配到的 "foo" 都替换成 "bar",并在每次替换前询问用户是否确认。

Linux编译器-gcc/g++使用 

有些云服务器上可能没有g++。

安装g++:sudo yum install -y gcc-c++

  • 对于云服务器,默认是ceonos 7.6 or 8,默认匹配的gcc版本是4.8对于目前是完全够用的。
  • 编译器gcc是一个专门用来编译链接C语言的。
  • 编译器g++是一个专门用来编译链接C++语言的。
  • C++兼容C所以g++也可以编译C。

背景知识

  1. 预处理(1.头文件展开、2.去注释、3.宏替换、4.条件编译等)
  2. 编译(C/C++代码翻译成汇编语言)
  3. 汇编(汇编代码转为可重定向二进制目标代码 - 生成机器可识别代码)
  4. 连接(链接 -> 多个.0,.obj -> 合并形成一个可执行.exe等)   

从Linux的基础上理解:
首先用vim写一个简单的C语言文件。

#include <stdio.h>

#define NUM 100

int main()
{
    printf("NUM: %d", NUM);
    printf("NUM: %d", NUM);
//  printf("NUM: %d", NUM);
//  printf("NUM: %d", NUM);
//  printf("NUM: %d", NUM);
//  printf("NUM: %d", NUM);
//  printf("NUM: %d", NUM);
    printf("NUM: %d", NUM);
    printf("NUM: %d", NUM);
    return 0;
}

gcc如何完成

  • 格式 gcc  [选项]  要编译的文件  [选项]  [目标文件]

一步达成

        注意-o后必须紧跟形成的可执行程序。

补充:

        不加-o,gcc默认生成a.out可执行程序。

Note:

        后面讲解的都是到哪一个阶段,所以:可以源文件到汇编阶段,预处理到汇编阶段。所以操作文件可以是 .c 也可以是 .i,反正是前面的步骤即可。

完成到第一步:预处理

        -E从现在开始进行程序的翻译,如果到预处理完成就停下来

        只使用-E,不适用-o生成目标文件会打印到屏幕上。

         可以使用vim编译器打开test.i

        我们可以发现,我们就写了几行代码,但是这却有

1. 头文件展开

#问:为什么突然会多这么多?

        不管是我们直接写程序,还是用库,都会包含C头文件或者是C++头文件。当我们实际在做编译的时候,对应的头文件的内容,是会拷贝到我们的源文件中的,所以头文件是需要编译的,在预编译的时候就会拷贝到对应的位置。所以,头文件为了防止重复拷贝也就会使用

  • 条件编译(举例如下:根据文件名命名就可以了)

#ifndef _HEADERNAME_H
#define _HEADERNAME_H
...//(头文件内容)
#endif

        当头文件第一次被包含时:它会被执行,而符号_HEADERNAME_H被定义为1。如果头文件被再次包含,通过条件编译,它的内容被忽略(头文件内容)。

  • #pragma once

        并且也因为头文件里还包含的有其他头文件,于是也就更多了。

2. 去注释

3. 宏替换

4. 条件编译

        因为Linux默认下为release

Note:

        通过上面的观察,我们可以知道预处理阶段其实还是C语言 / C++语言

完成到第二步:编译

        -S从现在开始进行程序的翻译,如果到编译完成就停下来

        可以使用vim编译器打开test.i

Note:

        通过上面的观察,我们可以知道编译阶段变为了汇编语言

完成到第三步:汇编

        -c从现在开始进行程序的翻译,如果到汇编完成就停下来

        可以使用vim编译器打开test.o

Note:

        通过上面的观察,我们可以知道汇编阶段变为了二进制语言

完成到第四步:链接

        也就是我们之前所写的一步达成。

链接 - 静态库与动态库

        其实在生成可执行程序之后,可执行程序其实也还是依赖着C语言 / C++语言库的。

一般链接的过程,是有两种方式的:

  1. 动态链接 - 需要动态库
  2. 静态链接 - 需要静态库

#问:这个代码能不能编译过?

int main()
{
    return 0;
}

        是能编译过的。

        Linux下是会保存C / C++需要使用的头文件的。 云服务器在路径/usr/include下:

        平时我们所写的代码,就以最简单的为例:打印hello world。我们使用printf函数打印字符串"hello world\n",我们是实现printf函数了吗?并没有,但是他有被调用了,证明一定有实现体,这就是因为C语言提供的。C语言通过头文件提供的。更直接的说,其是通过库供给我们使用的。

        云服务器下的库路径/lib64/下:

        包含了Linux下的大部分动静态库,就是因为有动静态库的存在,所以我们才可以通过头文件找到方法的声明,再到当中找到方法的实现将我们的代码与库中的代码关联起来,才形成了一个可执行程序。

Linux:

        .so(动态库)

        .a(静态库)

windows:

        .dll(动态库)

        .lib(静态库)

#问:那么我们安装VS2019、VS2022的组件安装是在干什么?

        也就是安装C / C++所要依赖的头文件与库罢了。

总结:

        也就是说,当我们的源文件编译到汇编后,形成的目标可重定向二进制文件,这一步只是将我们直接所实现的代码编译完了(文本到二进制)。而编译的链接就是为了将我们代码当中未和库关联起来的部分关联起来,最后我们的程序才能执行。(编译的链接可以理解为printf之类的地址是未定义的)

动态库 - 动态链接

        一个故事理解:一个同学他刚刚初中毕业,上了一所高中,他想完电脑,但是因为学校不允许有电脑,于是没有办法带着。但是一个人告诉他有一个网吧转弯过去就是。于是这个同学知道了这个网吧的地址,但是不知道是怎么样的网吧,但是他记住了,于是他立了一个计划:

  1. 上课 - 上数学课干什么等(程序员所自己写的函数的实现)
  2. 写作业 - 写数学作业等(程序员所自己写的函数的实现)
  3. 去网吧上网(C语言提供了一个函数,编译的时候知道存在,但是不知道实现,就如同这位同学只知道这个网吧的地址。C语言告诉程序员有这个实现,一个人告诉同学有这个网吧)

        于是同学到执行这个计划的时候,就根据这个地址,跑去网吧找电脑了。也就是编译根据地址跑去找动态库。

静态库 - 静态链接

        一个故事理解:这个同学上大学了,学校允许带电脑了,这个时候,他将原本高中时的电脑买了一个,于是将电脑带在了身边,这个时候,他立了一个计划:

  1. ……(程序员所自己写的函数的实现)
  2. 用自己的电脑上网(电脑已经在身边了,将网吧的电脑带在了身边,就不用根据地址找电脑了。如同程序数据直接放在了需要的位置,不用根据地址去找寻了)

        于是同学到执行这个计划的时候,直接拿出了身边的电脑。也就是编译已经将数据在所需的地方了。

动态链接 - 静态链接

        一个故事理解:这样的同学很多,于是跑网吧,这个时候一台电脑可以多人用(一个电脑可以多人玩),而带在身上,就一个同学一个电脑。所以比起来动态链接,静态链接更节省空间。

总结

  • 动态链接:将库中我们要的方法的地址,填入我们的可执行程序中,建立关联 —— 节省空间。
  • 静态链接:将库中我们要的方法的实现,真的拷贝到我们的可执行程序中 —— 占用空间。

云服务器有可能没有

C静态库安装:sudo yum install -y glibc-static

C++静态库安装:sudo yum install -y libstdc++-static

gcc选项

  • -E 只激活预处理,这个不生成文件,你需要把它重定向到一个输出文件里面
  • -S  编译到汇编语言不进行汇编和链接
  • -c  编译到目标代码
  • -o 文件输出到 文件
  • -static 此选项对生成的文件采用静态链接
  • -g 生成调试信息。GNU 调试器可利用该信息。
  • -shared 此选项将尽量使用动态库,所以生成文件比较小,但是需要系统由动态库.
  • -O0 -O1 -O2 -O3 编译器的优化选项的4个级别,-O0表示没有优化,-O1为缺省值,-O3优化级别最高
  • -w  不生成任何警告信息。
  • -Wall 生成所有警告信息。

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

make和Makefile

  • make是一个命令
  • Makefile是一个文件

用于:自动化的构建项目。

背景

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

实例代码

编写Makefile:

  • 依赖关系
  • 依赖方法

利用依赖关系依赖方法,达到自动化的构建项目。

        在具有一定的依赖关系:二者具有一定联系、关系的事物。才能实现一定的依赖方法:因为这个一定联系、关系所才能达到一定事、任务。

依赖关系依赖方法

        伪目标:假的目标,为的就是实现下面的依赖方法。 

Note:

        使用make默认是执行第一个依赖关系与依赖方法。

        如果我们将Makefile改成下列这样的话。

         make只会自顶向下,扫描第一个目标文件。进行执行。

伪目标

        总是被执行的!

        如果将test也变为伪目标。

        这个时候其也可以变为总是被执行的!

总是被执行:

        总是会根据依赖关系,执行依赖方法!习惯:clean设置.PHONY

#问:Makefile是如何得知,我们的可执行程序是最新的?

        根据文件的最近修改时间的来的!

start命令查看时间

  • Acess:文件最近被访问的时间(如:修改)。
  • Modify:文件内容的改变时间。
  • Change:属性的改变时间(如:该权限)。

Note:

        Acess:文件最近被访问的时间,不一定打开文件然后关闭就改变。这是因为Linux操作系统对时间进行的调整,因为平时读取文件是一个高频操作,也就意味着Acess是被高频修改的。而文件处于磁盘,那么每一次修改Acess,都需修改文件处于磁盘对应的Acess数据。所以大量的IO就会耗费资源。所以,Linux进行了修改,是累积到一定的次数才会修改文件处于磁盘对应的Acess数据。

        而Makefile得知我们的可执行程序是最新的,是通过可执行程序比源文件新,那么只有源文件动内容了,才会导致源文件比可执行程序新,才会make成功。

Makefile的多文件使用:

test.h

#pragma once

#include <stdio.h>

extern void show();

main.c

#include "test.h"

int main()
{
    show();

    return 0;
}

test.c

#include "test.h"

void show()
{
    printf("hello test!\n");
}

        第一个目标文件就是利用链接实现,而其所依赖的方法中有两个目标文件,于是便会又去执行,两个目标文件各自的依赖方法。

Linux第一个小程序 - 进度条

第一个程序

第二个程序

        通过执行会发现,第一个程序是先打印出hello world,后sleep(3)。第二个程序是先后sleep(3),打印出hello world。

#问:难道是第二个程序printf比sleep后执行?

        不是,也不可能,一个程序的执行是按照一个代码一个代码来的,所以printf一定比sleep先执行。并且是早就执行完了!

        只不过是信息("hello world")没有被立马显示出来!C语言是会给我们提供输出缓冲区(就是C语言给我们提供的一段内存空间)的,根据特定的刷新策略,来进行刷新!

        显示器设备,一般的刷新策略是行刷新,是碰到"\n",就立马将"\n"之间的所有的字符全部的显示出来。

         我们可以使用fflush将缓冲区的数据立马进行刷新。

        在语言级的学习中,就提到过C语言其实是默认打开三个文件的。标准输入标准输出标准错误stdout就是标准输出,就是显示屏,意思就是将缓冲区数据立马刷新到屏幕上。

\r&&\n

\r

\n

        所以,我们平时生活中所想的换行,其实在计算机本质是:换行 + 回车。所以这也是键盘走式Enter原因:

        我们所写的"\n"之所以会变为,换行 + 回车的情况,是因为C语言中的,编译器编译的时候默认就将"\n"变为了回到开头 + 换行

进度条代码

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

#define NUM 102

int main()
{
    char bar[NUM];
    memset(bar, 0 ,sizeof(bar));
    const char *lable="|/-\\"; //4符号
    int cnt = 0;
    while(cnt <= 100)
    {
        printf("[%-100s][%d%%] %c\r", bar, cnt, lable[cnt%4]);
        bar[cnt++] = '#';
        fflush(stdout);
        usleep(30000);
    }
    printf("\n");
    return 0;
}

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

川入

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值