当前位置: 首页 > news >正文

2. Linux开发工具

目录

1.vim

1. vim的基本概念

2. vim的基本操作

3. vim命令模式命令集

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

3. Linux项目自动化构建工具-make/makefile

makefile:

make:

项目清理:

4.Linux小程序-进度条

5. git命令行

6. Linux调试器-gdb


1.vim

  • IDE-vscode,jetbrains等编写,编译,输出结果为一体的
  • vim只是写代码的工具

1. vim的基本概念

目前我们掌握三种即可,分别是命令模式、插入模式、底行模式,各模式的功能区分如下:

  • 正常/普通/命令模式(Normal mode)

控制屏幕光标的移动,字符,字或行的删除,移动复制某区段及进入Insert mode、Last lint mode

  • 插入模式(Insert mode)

只有在Insert mode下,才可以做文字输入,按[ESC]回到命令行模式

  • 末行模式(Last lint mode)

文件保存或退出,也可以进行文件替换,找字符串,列出行号等操作。在命令模式下,shift+;(其实就是:)即可进入该模式。

2. vim的基本操作

  • 进入vim,在系统提示符号输入vim及文件名称后,就进入vim全屏幕编辑画面:
vim test.c

进入vim以后是命令模式,要切换到插入模式才能输入文字。

  • 命令模式切换到插入模式
    • 输入a:从目前光标所在位置的下一个位置开始输入
    • 输入i:从光标所在位置输入
    • 输入o:插入新的一行,从行首开始输入文字
  • 退出vim及保存文件
    • w保存当前文件
    • wq+回车:保存并退出
    • q!:不存盘强制退出vim

3. vim命令模式命令集

进入插入模式和末行模式上面讲了,这里主要看其他的:

移动光标:

  • vim可以使用小键盘的上下左右进行移动,但正规的vim是用小写英文字母h、j、k、l分别控制左、下、上、右的
  • G:移动到最后
  • $:所在行行尾
  • ^:所在行行首
  • w:下个字开头
  • b:回到上个字开头
  • gg:跳到文本开头
  • 行号G:定位光标到任意行

删除:

  • dd:删除光标所在行(剪切),dd+p就是剪切加复制,不p就是删除

复制:

  • yy:复制光标所在行到缓冲区
  • p:将缓冲区内字符粘贴到光标所在位置的下一行
  • yy+10p:复制10行

替换:

  • r:替换光标所在字符(不需要删除再打新的)
  • R:替换光标所在字符,按下ESC为止
  • shift+~

撤销:

  • u:撤回,例如Windows的ctrl+z
  • ctrl+r:撤销的恢复

多行注释和取消注释:

  • 多行注释:在命令模式下,ctrl+v,hjkl上下左右移动选中多行代码(不能用箭头),大写i,//,ESC
  • 取消注释:在命令模式下,ctrl+v,hjkl上下左右移动选中多行代码,d

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

gcc专用于编译C程序,g++是C和C++的都可以。

预处理:

  • 功能包括:宏定义、文件包含、条件编译、去注释等(所以宏没机会进行语法检查,还没到检查的那个阶段就被替换了,不存在宏了)
  • gcc -E hello.c -o hello.i
  • -E:让gcc在预处理结束后停止编译过程
  • -o:是指目标文件,意思是处理后的文件命名为xxx
  • .i文件:为已预处理过的C源程序

编译:

  • 检查语法,检查无误后,gcc把代码翻译成汇编语言
  • gcc -S hello.i -o hello.s
  • -S:让gcc在编译完后停下来,生成汇编代码

汇编:

  • 把编译阶段生成的汇编代码转化为二进制机器码
  • gcc -c hello.s -o hello.o(.o文件不能独立执行,需经过连接)

连接:

  • 生成可执行文件
  • gcc hello.o -o hello

连接中涉及到一个关键概念:函数库:

举个例子:我们的程序中没有定义pritf,只是包含了stdio.h,而这个文件中也只有printf的声明,并没有它的实现,那printf在哪里实现的呢?

系统把这些函数的实现都放到C标准库(如libc.alibc.so)中,这个库本身是一个文件,gcc会默认到这个lib路径下进行查找,也就是连接到那个函数库中去,这样就能调用printf了。

函数库一般分为静态库和动态库,linux中.so是动态库、.a是静态库。

  • 静态库是指编译链接时,把库文件的代码全部加入到可执行文件中,因此生成的文件比较大,但在运行时也不需要库文件了,它的优点是不依赖库,可独立运行
  • 动态库相反,是程序执行时,才连接库,节省系统的开销
  • gcc在编译时默认使用动态库,是动态链接的,若要按静态链接方式,要添加-static选项

-static的本质:改变优先级。一个文件(可执行程序或库)不一定是纯动态链接或纯静态链接,实际应用中往往是混合链接的。

3. Linux项目自动化构建工具-make/makefile

        一个工程中的源文件非常多,makefile指定了一系列依赖来指定,哪些文件先编译,哪些文件后编译,用gcc不方便,makefile的好处就是自动化编译,一旦写好,只需要一个make命令,就可以完成整个工程的自动编译,极大提高效率。

make是一条命令,makefile是一个文件,两者搭配使用。

makefile:

makefile中包含依赖关系和依赖方法,举个例子

1,3,5,7即为依赖关系,2,4,6,8为依赖方法。

那什么是依赖关系呢?依赖关系指定了目标(target)所依赖的文件或其他目标。

        比如第一行中,mycode就依赖mycode.o,前面的依赖后面的,这一行是声明这一种关系,就好比我和我爸,我依赖我爸,我不能依赖别人爸,我没生活费了需要我爸给我打钱,而不是别人爸给我打钱。先得产生关系,才能有具体的行为。也就是先得有依赖关系,才会调用对应的依赖方法。

        在上面的makefile中体现出的就是,想要mycode,就得有mycode.o,想要mycode.o就得有mycode.s,想要mycode.s就得有mycode.i,想要mycode.i就得有mycode.c。他会一层一层向下找,最后返回,这是一个有点像递归的执行方式。

make:

        make会在当前目录下找到名为makefile或Makefile的文件,找到之后,他会找文件中的第一个文件,也就是第一个依赖关系中前面的那个文件,作为目标文件。在上面的例子中,他会找到mycode 这个文件作为目标文件。

        如果没有mycode,那他就会找mycode依赖的文件,层层递推,直到最终编译出第一个目标文件。

make完以后,再make就不会再编译

[zzy@iZuf626dg02ts3xac27i6sZ processBar]$ make
gcc -o processbar processBar.c main.c
[zzy@iZuf626dg02ts3xac27i6sZ processBar]$ make
make: `processbar' is up to date.

为什么只能make一次呢?

        文件没改变过再make也没用,还是一样的结果,所以为了提高编译效率,make过就不能再make了。

那这是怎么判断一个工程能否再make的呢?它怎么直到文件是否被更改过呢?

        在make时,一定是源文件形成可执行文件,先有源文件,才有可执行文件,所以一般情况下,源文件的修改时间一定比可执行文件的修改时间更早。如果我们修改了源文件,曾经还有可执行,那么源文件的修改时间肯定是更新的。

        所以只需要比较:可执行程序的最近修改时间 和 源文件的最近修改时间

如果 .exe 新于 .c,即.c源文件是老的,那么就不需要重新编译

如果 .exe 老于 .c,即.c源文件是新的,那么就需要重新编译

make 会根据源文件和目标文件的新旧,判定是否需要重新执行依赖关系进行编译。

[zzy@iZuf626dg02ts3xac27i6sZ processBar]$ stat makefileFile: ‘makefile’Size: 84        	Blocks: 8          IO Block: 4096   regular file
Device: fd01h/64769d	Inode: 1057038     Links: 1
Access: (0664/-rw-rw-r--)  Uid: ( 1000/     zzy)   Gid: ( 1000/     zzy)
Access: 2025-04-13 13:59:54.742513605 +0800
Modify: 2025-04-13 13:59:51.491393878 +0800
Change: 2025-04-13 13:59:51.491393878 +0800Birth: -

调用stat可以显示出一个文件的各种信息,可以发现下面有3个时间:

Access time (atime): 表示文件的 最后访问时间,即文件内容最后一次被读取的时间。

Modify time (mtime):这是文件内容最后一次被修改的时间(比如用编辑器修改并保存了 makefile)。

Change time (ctime): 这是文件元数据(如权限、所有者等)最后一次被修改的时间。

        上一章文件包括文件内容和文件属性,修改文件内容就会修改mtime,修改文件属性就会修改ctime。一般修改文件内容,文件的大小变了,那么文件的属性也变了,即mtime变了,ctime也会变。若只修改文件属性,比如权限,则只有ctime变了。

再有一点:如果我们想把一个已存在文件的时间更新为最新,可以使用touch:

[zzy@iZuf626dg02ts3xac27i6sZ ~]$ touch makefile[zzy@iZuf626dg02ts3xac27i6sZ ~]$ stat makefileFile: ‘makefile’Size: 76        	Blocks: 8          IO Block: 4096   regular file
Device: fd01h/64769d	Inode: 921073      Links: 1
Access: (0664/-rw-rw-r--)  Uid: ( 1000/     zzy)   Gid: ( 1000/     zzy)
Access: 2025-04-13 15:59:52.086643597 +0800
Modify: 2025-04-13 15:59:52.086643597 +0800
Change: 2025-04-13 15:59:52.086643597 +0800Birth: -

那如果我就是想不管新旧都能make呢?可以这样写makefile:

我们用.PHONY修饰目标文件,成为伪目标,伪目标的特性:总是被执行的。不过我们不建议这么搞,但是清理是希望总被执行的。

项目清理:

        工程是需要被清理的,clean没有依赖文件,调用时直接make clean就可以了,清除所有目标文件,方便重新编译。

        注意clean一般要写到最后,如果写到最开头的话,make这个命令就会把clean当作目标文件,调用make等于调用make clean了。

4.Linux小程序-进度条

先理解一下回车和换行:

回车:回到一行的最开始

换行:换到下一行

现代电脑键盘都把这两个操作合并成回车键了,老式的打印机:

纸向上移动的过程就是换行的过程,左边这个拨片在打字时会向右走,走到头需要手动的拨回最左边,这就是回车的过程。

再理解一下行缓冲区:
运行如下代码会发现:先休眠了2s,才打印出的hello world,但是程序的执行顺序一定是先执行打印,为什么没能在屏幕上输出来呢?

[zzy@iZuf626dg02ts3xac27i6sZ ~]$ cat test.c
#include <stdio.h>int main()
{printf("hello world");sleep(2);return 0;
}

sleep时,printf一定执行完了,hello world此时就存放在缓冲区stdout,默认只有程序结束时才会刷新缓冲区,将其中的内容输出。

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

我们可以使用fflush提前将缓冲区中的内容刷新出去就实现了先打印,再休眠。

进度条代码:

processBar.h:

#pragma once#include <stdio.h>#define NUM 102
#define STYLE '-'extern void processbar();

processBar.c:

#include "processBar.h"
#include <string.h>
#include <unistd.h>void processbar()
{int cnt = 0;char bar[NUM];memset(bar, '\0', sizeof(bar));const char* lable = "|/-\\";int len = strlen(lable);while(cnt <= 100){printf("[%-100s][%d%%][%c]\r", bar, cnt, lable[cnt%len]);fflush(stdout);bar[cnt++] = STYLE;if(cnt < 100)bar[cnt] = '>';usleep(100000);}printf("\n");return;
}

label是在进度条末尾显示一个 | / - \ 的循环,其实就是一条线在转的效果,表示进度条在动。

main.c

#include "processBar.h"int main()
{processbar();return 0;
}

5. git命令行

准备工作:创建gitee账号,创建仓库,linux中安装好git

把创建好的仓库克隆到本地:

git clone https://gitee.com/want-to-become-a-coding-expert/linux.git

 后面的地址复制的是下面这个按钮里的https

这时候ll就可以发现有了这个库为名称的目录

那怎么把刚刚写的进度条上传到gitee中呢?

1. 首先把 processBar 拷贝到仓库中,进到linux中,然后:

cp ../processBar . -rf

2. 把仓库中不存在的存入到暂存区:

git add .

3. 把暂存区中的内容放到版本库中:

git commit -m "提交日志:不能乱写,要写干了什么"

4. 推送到远端-gitee创建的仓库中

git push

然后输一下登陆gitee时的账号和密码就行了。

其他问题:

查看提交仓库历史记录:

git log

检查是否有新文件没有推送,需要更新,即检查工作目录状态:

git status

首次使用时需要配置邮箱和用户名,这个邮箱最好和gitee绑定的一样。这主要是为了代码溯源,如果提交上去的代码有问题,或者别人用的时候发现了问题方便找到是谁提交的。

其他还有很多命令,使用方法,可自行了解,后期可能也会单独写git企业级系列吧。

6. Linux调试器-gdb

程序的发布方式有两种,debug和release版本。

linux gcc/g++出来的可执行程序,默认是release模式,不能使用gdb调试,要使用gdb调试,必须在makefile中,加上-g选项,debug发布。

在实际调试中:
首先得先看到程序:

  • l 行号 : 显示行号附近的代码,每次列10行

一般使用时 l 0,然后一直回车就可每次列10行直到全部列出

  • r:运行程序
  • c:从当前位置开始运行到下一个断点
  • b 行号:在某一行设置断点
  • info break:查看断点信息,其中含有一个断点序号
  • d 序号:可以删除某序号的断点
  • d b : 删除所有断点
  • disable b 序号:可以禁用某个断点,就是不删但是暂时不想用
  • enable b 序号:启用断点
  • s:进入函数体内部,逐语句进行调试
  • finish:执行到当前函数返回,然后停下来,其实就是某个函数直接跑完
  • until 行号:快速运行代码到指定行
  • p 变量:打印变量值
  • display 变量:可以跟踪查看一个变量,每次停下来都会显示它的值(可以跟踪多个)
  • undisplay 变量序号:取消追踪变量,注意后面跟的是变量序号不是变量名
  • n:单步执行
  • q:退出调试

相关文章:

  • 亚远景-如何通过ASPICE评估满足功能安全(ISO 26262)合规需求?
  • OFDM 信道表示(3)
  • 【网络安全】网络钓鱼的类型
  • React:什么是Hook?通俗易懂的讲讲
  • MuJoCo 机械臂 PPO 强化学习逆向运动学(IK)
  • 分页查询优惠券
  • 逐步了解蓝牙 LE 配对(物联网网络安全)
  • Missashe考研日记-day26
  • istio使用ingress gateway通过header实现对不同服务的路由
  • Vue3 中 computed的详细用法
  • 达梦DMDSC初研
  • 【C语言】数据在内存中的存储:从整数到浮点数的奥秘
  • 1️⃣6️⃣three.js_光源
  • 大语言模型时代,单细胞注释也需要集思广益(mLLMCelltype)
  • 数字人接大模型第一步:表情同步
  • STM32 串口USART
  • 【嵌入式系统设计师(软考中级)】第二章:嵌入式系统硬件基础知识(2)
  • Concepts (C++20)
  • 如何在 Postman 中,自动获取 Token 并将其赋值到环境变量
  • 每日c/c++题 备战蓝桥杯 ([洛谷 P1226] 快速幂求模题解)
  • 朱守科任西藏自治区政府副主席、公安厅厅长
  • 吏亦有道|秦汉的发明家与技术传承
  • 长三角议事厅|国际产业转移对中国产业链韧性的影响与对策
  • 全球84%的珊瑚礁已遭受白化事件影响
  • 央行上海总部:上海个人住房贷款需求回升,增速连续半年回升
  • 嫦娥五号月球样品将借给这些国家机构