科普:开发流程
一个项目开发:项目经理 + 产品经理 + 程序员 + 测试(可能有)--->(开发团队)
产品经理提出来需求 --->>> 项目经理分配任务 ---> 程序员开发 --->>> 测试部门提交--->>> 项目经理发布任务
gdb调试:
假设当前我们有mycode.c文件
cpp
#include<stdio.h>
int addTOTop(int top)
{
int res = 0;
int i = 1;
for(;i <= top;i++)
{
res += i;
}
return res;
}
int main()
{
printf("debug begin\n");
int top = 100;
int sum = addTOTop(top);
printf("sum:%d\n",sum);
printf("debug end\n");
return 0;
}
和对应的makefile文件用来做演示:
bash
mycode:mycode.c
gcc -o $@ $^ -g
.PHONY:clean
clean:
rm -rf mycode
gdb mycode
可以查看mycode为名的可执行程序!(此时进入gdb交互模式)
gdb的基本操作:
- 输入q可以退出!
- 输入l / list可以查看该可执行程序的源码!(默认显示十行,如果此时未显示完全,继续按回车即可!)(但是有时候不是从第一行开始显示!如果想要从第一行开始显示,直接l0!)
- l 1 从第一行开始;l 2 从第二行开始!
- l 0之后只会默认显示10行;此时gdb会默认记录使用过的代码,因此此时直接回车会默认执行l选项!
- l + 函数名可以查看对应函数的代码!例如 ---> l addTOP
- r --->表示运行程序!
- 设置断点:b 19(b+ 行号!)(在第19行处打断点)
1、查看断点的信息
info b
此时可以查看断点信息!
- 第一行的Num表示断点的编号!
- Enb表示是否开启
- Address表示断点的地址
- What显示断点位于程序的哪个位置
2、删除断点
-
删除的时候使用d + 断点编号来删除(不能用行号!)
d 1
如果我们设置好断点后将gdb关闭,然后重新打开gdb,此时我们设置的断点会消失!
设置完断点后再使用r运行程序,会自动运行到我们设置的断点处!
3、逐过程和逐语句
在VS中,F10为逐过程;F11为逐语句!
在gdb中,逐过程用n (next)表示(逐过程会直接跳过函数,不进入函数调用,且gdb会自动跳过空行,进入到下一段代码处)
调试结束后断点还存在!且此时info b 会更新断点被调试次数的信息!
且gdb会自动记住历史命令! --- > 直接回车代表用上一条命令!
s
s表示(step) --->逐语句调试过程,可以进入到函数内部进行调试!
对于普通的语句来说,逐过程(n)和逐语句(s)是没有区别的!
4、查看对应变量值 (p + display)
vs中可以调用监视窗口,在gdb上使用p + 变量值查看对应的变量内容
p i
可以查看i的变量值!
如果我们想要长显示变量的值 (一直显示变量的值),可以使用display + 变量名
display i
作用等同于监视!
长显示最左边有对应的编号!如果我们想要取消长显示undispaly + 编号!
undispaly 3
可以对res取消显示!
5、跳过指定行
如果我们进入到函数内部,此时我们想要跳转出来 ,可以使用until指令使得跳过对应行:
until可以从一个函数跳转到指定行!
例如
until 10
此时代码会跳转到第11行!(如果第10行为空行!)
6、运行完函数后停止
如果此时我们只想函数运行下来后停止,不要再往后面走,只想要验证整个函数的运行情况,可以使用finish指令直接运行完整个函数!
作用:如果一个函数没有问题,则会正常运行完后停下来,如果一个函数有问题,此时会运行中断,帮助我们找到有问题的部分!
7、从一个断点处运行到另一个断点处
如果我们想要从一个断点处运行到下一个断点处:c(continue)
如果此时断点2运行到断点3报错,说明错误在断点2和断点3之间,可以在2和3之间大更细致的断点找错误(中间可以进入函数使用finish查找错误等等)
8、禁用断点
在vs中,当我们设置一个断点的时候,右键可以选择禁用该断点(虽然断点被创建但此时断点不发挥作用)
在Linux系统中:
bash
disable 2
此时2号断点会被禁用!
此时可以发现2号断点的Enb状态由y变为n
如果我们此时想把断点1打开:
bash
enable 1
此时Enb状态会变成y!
9、在指定位置打上断点
b + 函数名会直接将断点打在函数内部起始的第一个位置!例如:
bash
b main
还可以直接对一个.c文件打断点:
bash
b mycode.c:19
直接对mycode.c的第19行打断点!
还可以对文件名内的函数打断点:
bash
b mycode.c:main
10、设置变量名
set可以设置一个变量名的值:
bash
set var + 变量名 值
例如我们进入一个循环中,此时我们需要循环快速接近结尾:
bash
set var i = 97
11、 补充
breaktrace (bt) --- 查看各级函数调用堆栈及参数(只有进入函数中才能查看!)
info locals --- 查看当前栈帧局部变量的值(只有进入函数中才能查看!)
认识冯诺依曼体系结构
一、先谈硬件
一个计算机要能正常工作,它的体系结构必须遵循冯诺依曼体系结构!
一般寄存器指的就是内存!
硬盘/U盘等可以叫做外存,外存的构造与内存相差特别大,一般硬盘/U盘当作输入输出设备!
输入设备: (计算机只认识二进制!因此人类无法直接访问内存!)鼠标,键盘,摄像头,话筒,磁盘(不一定用户自己输入,还可以从文件中读取),网卡(计算机从网络中收到消息 --- 网卡先收到!)
输出设备:(将二进制转化为人能读懂的字符/视频)显示器,磁盘(文件写完后保存到磁盘上),网卡(将信息发送给他人)
有的设备是纯输入 / 输出,有的设备既是输入又是输出!输入设备和输出设备统称为外设!
运算器:对我们的数据进行运算任务(算术运算 / 逻辑运算)
控制器:对我们的计算硬件流程进行一定的控制(什么时候输入,什么时候输出)
控制器 + 运算器就是中央控制器,也就是我们说的CPU!
这五个部分都是一个独立的个体!可以拆分下来!
各个硬件单元必须用线连接起来,这个"线"也就是总线!
总线分为两种:1、系统总线 2、IO总线
CPU和内存直接交互的线被称为系统总线!
内存和外设(输入输出设备)连接的总线被称为IO总线!
回忆:指针中分配地址有地址总线和控制总线
有的总显示裸漏在外面的可以看到,有的总线是集成在电路上看不到!
SSD:固态硬盘
HDD:机械硬盘
金字塔从上到下,容量越来越大,访问速率越来越慢
CPU内的寄存器,访问速度为纳秒级别;内存是微秒级别;硬盘是毫秒级别;
为什么要有存储器?
因为外设和中央处理器之间的代差太大了!可以参考木桶原理!(一个木桶的最高容水量取决于最短的那块板子!)
如果直接让外部设备直接和中央处理器交互,那么整个计算机直接的交互效率就以输入输出设备的效率为主!(中央处理器很快就处理完数据,但是输入/输出设备会一直慢悠悠的输入/输出数据!)因此如果没有存储器,会导致整机效率非常低下!
CPU与内存和内存与输入输出设备直接也有代差,但是这个代差相较于外设和中央处理器之间小很多!最后整机效率以内存效率为主!
加了存储器之后,需要将输入设备传入存储器,存储器再交给运算器和控制器后进行计算,然后再返回给存储器,再交给输出设备(串行!)
输入设备可能会提前将数据预加载到存储器!CPU的加载和计算可以同时进行!
可以将存储器(内存)看做一个硬件级别的缓存空间!
一个程序要运行,必须加载到内存中运行!为什么?
一个程序中包含有代码和数据,必须被CPU去执行!而CPU只从内存中拿数据!(冯诺依曼体系结构规定!) --- > 所有的软件结构必须遵循硬件体系结构!
为什么我们当时写的进度条,默认显示的数据,是可能被缓存起来的?在那里缓存?
遵循冯诺依曼体系结构,从CPU输出到内存中,在内存中缓存,然后再刷新到输出设备中!
情景猜想:
QQ是在内存中的!(登录上QQ软件的时候!)
在"我"的输出设备中,发消息时最主要的还是将消息输出到网卡,显示器此时为同步的一份!
在"我"的CPU中,可能对数据进行压缩打包等一系列操作;
在"朋友"的CPU中,可能对数据进行解包解压等一系列操作;
如果我们此时想要发送一份实验报告给对方,是怎么实现的?
"朋友"收到实验报告后,并不能直接打开,而是需要下载!而且关闭QQ后再次打开,还能够继续下载!
CPU和内存是不能一直保存数据的,因此实验报告是被存放在了内存中!因此传送文件的本质就是从一个磁盘拷贝到另一个磁盘!
二、操作系统
概念:
操作系统是一款进行管理的软件!
任何一个计算机系统都包含一个基本的程序集合,称为操作系统(OS),操作系统可分为两部分:
- 内核(进程管理,内存管理,文件管理,驱动管理)
- 其他程序(例如函数库,shell程序等等)
目的:
底层的硬件都采用的冯诺依曼体系结构,而硬件与操作系统之间需要通过驱动程序连接起来!
1、管理好下面的软硬件资源!
2、为了给用户提供一个良好(稳定、高效、安全)的运行环境!
总结:操作系统通过管理好底层的软硬件资源(手段),为用户提供一个良好的执行环境(目的)
操作系统里面会有各种数据,但是,操作系统不会信任任何用户!(类似银行)
操作系统为了保障自己的数据安全,也为了保证给用户能提供服务,操作系统以接口的方式给用户提供调用的入口,来获取操作系统内部的数据!(类似于银行的小窗口!)
操作系统本质是C语言实现的!
接口是操作系统提供的用C语言实现的,自己内部的函数调用!这个接口也被称为系统调用!
所有的访问操作系统的行为,都只能通过系统调用完成!
但是,系统调用用起来比较麻烦,因此有人对系统调用做了各种功能的封装 --- > 用户操作接口!