系统编程之基础知识篇
操作系统是把计算机的硬件管理起来,让硬件正常运行
CPU(运算器 控制器 寄存器组) 内存(主存) 存储(硬盘,移动硬盘,U盘) 键盘和鼠标 显示器
从内存中取一条指令
通过控制器译码
把指令发送给CPU运算器
CPU运算器进行逻辑和数据运算
把运算的结果发送到内存
取址 译码 运算
运算器 数据运算
控制器
MAR 内存地址寄存器
MBR 内存缓冲寄存器
IO AR IO地址寄存器
IO BR IO缓冲寄存器
PC 程序计数器
PSW 程序状态寄存器
控制器主要是和内存数据传递,控制器和内存的读写速度不一致,引入了cache
寄存器组
专有寄存器组和通用寄存器组,编程是程序可以读写的是通用寄存器组 AX BX CX DX
控制寄存器
数据寄存器
状态寄存器
地址总线:是系统的位数,也说明了寻址空间,比如32位系统寻址空间是2^32=4G,64位系统2^64=2^32*2^32=2^32*4G
数据总线:计算机在处理数据时,并发或者同时处理数据的位数,可能是20位,24位
控制总线:中断 时钟 复位 IO读写 存储读写 系统总线请求
分2部分 操作码+运算数
1)4地址指令: OP A1 A2 A3 A4 + 把A1和A2的运算结果存储在A3中,A4是下一条指令
2)3地址指令:OP A1 A2 A3 把下一条指令存储在了PC寄存器
3)2地址指令:OP A1 A2 把A1和A2的运算结果存储在A1中, PC存储下一条指令
4)1地址指令:OP A1 ACC累加器 A1+ACC结果存储在ACC,PC存储下一条指令
5)0地址指令:OP SP堆栈指针
1)立即数寻址 mov r0,r1,#2
2)直接寻址 地址中存储的是数据 相当于一维指针
3)隐含寻址 ACC
4)间接寻址 地址中存储的还是地址,相当于二维指针
5)寄存器寻址
6)寄存器间接寻址
7)基址寻址 基址寄存器
8)变址寻址 变址寄存器
9)相对寻址 PC寄存器
10)堆栈寻址 SP
系统中的一个进程在运行,有优先级高的进程的时候,原来的进程暂停运行,优先级高的进程先运行,运行完后,中断返回,原来的进程继续运行
中断向量表
通过寄存器组,中断前把数据和程序运行状态保存在寄存器组中,中断之后,从寄存器组中把数据恢复出来,继续原来程序的运行
1)二进制思想
2)程序存储思想
计算机中的一切程序=二进制+上下文
1)阻塞 scanf() fgets() getchar()
2)非阻塞 中断,程序一直在循环查询中断向量表,等待中断的返回
从现象说,阻塞和非阻塞都是程序停止,不继续运行,但是从微观上说是有区别的
3)异步 DMA CPU告诉硬盘控制器某件事情,硬盘控制器开始完成这件事情,完成之后告诉CPU,在完成事情的过程中,CPU和硬盘控制器是各自忙各自的。硬盘控制器也具有CPU的一定功能了。
计算机系统分2层:应用层和内核层
系统调用是应用程序和系统内核数据传递的方法
应用程序把数据通过系统调用发送给内核,内核进行数据的运算,把运算的结果通过系统调用返回给应用程序
应用层相当于是客户端,内核层相当于是服务器
glibc库函数是封装的系统调用函数,封装了大部分的系统调用,但不是全部
glibc封装的函数更容易使用,更易于移植
比如,glibc库函数:fopen() fclse() fread() fwrite() fseek()
系统调用: open() close() read() write() lseek()
exit() glibc库函数
_exit() 系统调用函数
void exit(int status)
{
_exit(status);
printf("\n");//刷新缓冲区
return;
}
扇区 柱面 磁头
磁盘读写的方法:磁盘在旋转,磁头是按照一个扇区一个扇区读写的。
扇区:512字节
组:多个扇区组成组,1K 2K 4K
分区:多个组组成分区
1)按照字符读写
getchar() putchar()
2)按照行读写
fgets() fputs()
3)按照块读写
fread() fwrite()
4)循环读文件
while(fread(buf,sizeof(buf),1,fp)>0)
{
......
}
#include <errno.h>
char *strerror(int errno);
#include <stdio.h>
perror("fopen");
diff 比较2个文件是否相同
系统默热支持的最大文件描述符的个数是1024个
cat /proc/sys/fs/file_max
ulimit -n
ini文件
;stu
[stu]
zhangsan = 123456
lisi = 123456
;teacher
[teac]
wangwu = 123456
html文件
<!__stu__>
<stu>
zhansan=123456
lisi=123456
</stu>
<!__teac__>
<teac>
wangwu=123456
</teac>
ls -l
- 普通文件类型
d 目录
c 字符设备文件
b 块设备文件
s socket文件
p 管道文件
l 链接文件
软链接: ln -s oldfile newfile
硬链接: ln oldfile newfile
软链接:链接文件和源文件的inode节点编号不一样,是不同的文件,软链接相当于是快捷方式
硬链接:链接文件和源文件的inode节点编号一样,是同一个文件,但是硬链接是源文件的不同存在形式,如果需要删掉硬链接文件,需要删掉所有的硬连接和源文件,
链接文件和源文件,任何一个修改后,相应的文件内容都会修改
标准文件IO FILE *fp
系统文件IO int fd
系统启动后,有3个文件描述符已经分配好了
stdin 0 STDIN_FILENO
stdout 1 STDOUT_FILENO
stderr 2 STDERR_FILENO
文件描述符分配有个原则:最小的,未用的
比如说,0,1,2已经分配了,再分配的话,是3
如果说0,1,2,3,4,5,6,分配了,5关闭了,再分配是多少?是5还是7? 是5
标准文件IO只能打开普通文件,不能打开系统文件;系统文件IO不仅可以打开系统文件,还可以打开普通文件
1)open
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);
返回值:成功返回新的文件描述符,错误返回值是-1
pathname:是文件名或者绝对路径的文件名
flags:
O_RDONLY 可读
O_WRONLY 可写
O_RDWR 可读写
O_CREAT 如果文件不存在,则创建
O_TRUNC 每次写文件,重写
O_APPEND 追加
mode
111 111 111 777
110 100 100 644
当前用户 同组用户 其他组用户
0644 0是系统的粘着位
2)close
#include <unistd.h>
int close(int fd);
成功是0,错误是-1
3)read
#include <unistd.h>
ssize_t read(int fd, void *buf, size_t count);
fd:文件描述符
buf:从文件中读出的数据存放到什么地方
count:读出来的字节数
返回值:成功返回是读取的字节数;错误返回-1
4)write
#include <unistd.h>
ssize_t write(int fd, const void *buf, size_t count);
fd:文件描述符
buf:写的数据存放在什么地方
count:写的数据的长度是多少
返回值:成功返回的是写成功的字节数;错误返回-1
5)lseek
只对系统文件有效,对特殊的文件,比如管道,socket无效
#include <sys/types.h>
#include <unistd.h>
off_t lseek(int fd, off_t offset, int whence);
fd:文件描述符
offset:文件偏移量
whence:SEEK_SET SEEK_CUR SEEK_END
返回值:成功返回的是偏移量;错误返回 (off_t)-1