目录
文件属性获取
目录操作
标准IO 和文件IO 的区别
库
库的定义
库的分类
静态库
动态库
库的制作
制作静态库
动态库的制作
使用库
进程
程序和进程的区别
程序:编译好的可执行文件
进程:一个独立的可调度的任务
特点
进程段
进程分类
1.交互进程
2.批处理进程
3.守护进程
进程状态
进程状态切换图
就绪状态
执行状态
阻塞状态
文件属性获取
#include <sys/stat.h>
int stat(const char *path, struct stat *buf);
功能:获取文件属性
参数:path:文件路径名
buf:保存文件属性信息的结构体
返回值:成功:0
失败:-1
文件属性信息的结构体:
struct stat {
dev_t st_dev; /* 设备ID */
ino_t st_ino; /* inode号 */
mode_t st_mode; /* 文件类型和权限 */
nlink_t st_nlink; /* 硬链接数 */
uid_t st_uid; /* 用户ID */
gid_t st_gid; /* 组ID */
off_t st_size; /* 大小 */
time_t st_atime; /* 最后访问时间 */
time_t st_mtime; /* 最后修改时间 */
time_t st_ctime; /* 最后状态改变时间 */
};
stat的案例:
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <pwd.h>
#include <grp.h>
int main(int argc, char const *argv[])
{
struct stat st;
stat("./test.c", &st);
printf("%ld\n", st.st_ino);
printf("%ld\n", st.st_size);
printf("%ld\n", st.st_nlink);
if ((st.st_mode & __S_IFMT) == __S_IFBLK)
{
putchar('b');
}
else if ((st.st_mode & __S_IFMT) == __S_IFCHR)
{
putchar('c');
}
else if ((st.st_mode & __S_IFMT) == __S_IFDIR)
{
putchar('d');
}
else if ((st.st_mode & __S_IFMT) == __S_IFREG)
{
putchar('-');
}
else if ((st.st_mode & __S_IFMT) == __S_IFLNK)
{
putchar('l');
}
else if ((st.st_mode & __S_IFMT) == __S_IFSOCK)
{
putchar('s');
}
else if ((st.st_mode & __S_IFMT) == __S_IFIFO)
{
putchar('p');
}
// 文件权限判断
// 用户读权限
// if ((st.st_mode & S_IRUSR) > 0)
// {
// putchar('r');
// }
// else
// {
// putchar('-');
// }
// 文件权限掩码简化的方法
char arr[4] = "rwx";
for (int i = 0; i < 9; i++)
{
printf("%c", st.st_mode & (0400 >> i) ? arr[i % 3] : '-');
}
// 最后一次修改的时间
printf("%ld\n", st.st_mtime); // 得到的是秒数
// 用户名获取
printf("%s\n", getpwuid(st.st_uid)->pw_name);
// 组名获取
printf("%s\n", getgrgid(st.st_gid)->gr_name);
return 0;
}
目录操作
围绕着目录流进行操作,DIR *
#include <sys/types.h>
#include <dirent.h>
DIR *opendir(const char *name);
功能:获得目录流
参数:要打开的目录
返回值:成功:目录流
失败:NULLstruct dirent *readdir(DIR *dirp);
功能:读目录
参数:要读的目录流
返回值:成功:读到的信息
失败或读到目录结尾:NULL
返回值为描述该目录下的文件信息的结构体
该目录下的文件信息的结构体:
struct dirent {
ino_t d_ino; /* 索引节点号*/
off_t d_off; /*在目录文件中的偏移*/
unsigned short d_reclen; /* 文件名长度*/
unsigned char d_type; /* 文件类型 */
char d_name[256]; /* 文件名 */
};
int closedir(DIR *dirp);
功能:关闭目录
参数:dirp:目录流
标准IO 和文件IO 的区别
标准IO | 文件IO | |
概念 |
在C库中定义的一组输入输出的函数
|
在posix中定义的一组输入输出的函数
|
特点 |
1.有缓冲区,减少系统调用,提高效率
2.围绕流操作,FILE* 3.默认打开三个流:stdin\stdout\stderr 4.只操作普通文件 |
1.没有缓冲区,每次操作都引起系统调用
2.围绕文件描述符操作 3.默认打开三个文件描述符:0\1\2 4.除目录外其他文件 |
函数 |
打开文件:fopen/freopen
关闭文件:fclose 读写文件:fread,fwrite 文件定位:rewind/fseek/ftell |
打开文件:open
关闭文件:close 读写文件:read,write 文件定位:lseek |
库
库的定义
库:就是把一些常用函数的目标文件打包在一起,提供相应函数的接口,便于程序员使用;
本质上来说库是一种可执行代码的二进制形式
cd /usr/lib
lib:库文件cd /usr/include
include:头文件
由于windows和linux的本质不同,因此二者库的二进制是不兼容的
库的分类
静态库和动态库,本质区别是代码被载入时刻不同。
静态库
静态库在程序编译时会被连接到目标代码中。
优点:程序运行时将不再需要该静态库;运行时无需加载库,运行速度更快
缺点:静态库中的代码复制到了程序中,因此体积较大;静态库升级后,程序需要重新编译链接
动态库
动态库是在程序运行时才被载入代码中。
优点:程序在执行时加载动态库,代码体积小;程序升级更简单;
缺点:运行时还需要动态库的存在,移植性较差不同应用程序如果调用相同的库,那么在内存里只需要有一份该共享库的实例。
库的制作
制作静态库
1.将源文件编译生成目标文件
gcc -c add.c -o add.o
2.创建静态库用ar命令,它将很多的.o转换成 .a
ar crs libmyadd.a add.o
静态库文件名的命名规范是以lib为前缀,紧接着跟静态库名,扩展名为.a
3.测试使用静态库
gcc main.c -L. -lmyadd // -L指定库的路径 -l指定库名
执行:./a.out
动态库的制作
1-我们用gcc来创建共享库
gcc -fPIC -c hello.c -o hello.o
-fPIC 创建与地址无关的编译程序 (就是不和路径进行关联)
gcc -shared -o libmyhello.so hello.o
2-测试动态库使用
gcc main.c -L. -lmyhello
可以正常编译通过,但是运行时报错./a.out: error while loading shared libraries: libmyadd.so: cannot open shared object file: No such file or directory
原因:当加载动态库时,系统会默认从/lib或/usr/lib路径下查找库文件
解决方法(有三种):
(1)把库拷贝到/usr/lib和/lib目录下。(此方法编译时不需要指定库的路径)
(2)在LD_LIBRARY_PATH环境变量中加上库所在路径。
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:. (终端关闭,环境变量就没在了)
(3) 添加/etc/ld.so.conf.d/*.conf文件。把库所在的路径加到文件末尾,并执行ldconfig刷新
sudo vi xx.conf
添加动态库存在的路径使用绝对路径
使用库
将库文件放到系统目录/usr/lib 或 /lib
将头文件放在系统目录/usr/include
#include <xx.h> 如果头文件在当前目录
#include "xx.h" 如果头文件在其他目录
#include "头文件路径/xx.h" (如果我没有指定路径的话可以使用 gcc)
#include "xx.h" gcc xx.c -I 头文件的路径
-L 路径:指定库的路径
-l:(L的小写)指定库名
-I 路径:(i的大写)指定头文件路径
进程
程序和进程的区别
程序:编译好的可执行文件
存放在磁盘上的指令和数据的有序集合(文件)
程序是静态的,没有任何执行的概念
进程:一个独立的可调度的任务
执行一个程序所分配的资源的总称
进程是程序的一次执行过程
进程是动态的,包括创建、调度、执行和消亡
特点
1.系统会为每个进程分配0-4g的虚拟空间,其中0-3g是用户空间,每个进程独有;3g-4g是内核空间,所有进程共享
2.轮转调度:时间片,系统为每个进程分配时间片(几毫秒~几十毫秒),当一个进程时间片用完时,CPU调度另一个进程,从而实现进程调度的切换 (没有外界干预是随机调度)
进程段
"数据段" 存放的是全局变量、常数以及动态数据分配的数据空间(如malloc函数取得的空间)等。
"正文段" 存放的是程序中的代码
"堆栈段" 存放的是函数的返回地址、函数的参数以及程序中的局部变量
进程分类
1.交互进程
该类进程是由shell控制和运行的。交互进程既可以在前台运行,也可以在后台运 行。该类进程经常与用户进行交互,需要等待用户的输入,当接收到用户的输入后,该类 进程会立刻响应,典型的交互式进程有:shell命令进程、文本编辑器等
2.批处理进程
该类进程不属于某个终端,它被提交到一个队列中以便顺序执行
3.守护进程
该类进程在后台运行。它一般在Linux启动时开始执行,系统关闭时才结束
进程状态
1.运行态R:
指正在被CPU运行或者就绪的状态。这样的进程被成为running进程。
2.睡眠态:
可中断睡眠态S:处于等待状态中的进程,一旦被该进程等待的资源被释放,那么该进程就会进入运行状态。
(只能通过特定的函数进行唤醒,是不能随便去中断的)
不可中断睡眠态D:该状态的进程只能用wake_up()函数唤醒。
3.暂停态T:
当进程收到信号SIGSTOP、SIGTSTP、SIGTTIN或SIGTTOU时就会进入暂停状态。可向其发送SIGCONT信号让进程转换到可运行状态。
4.死亡态X:进程结束
5.僵尸态Z: 当进程已经终止运行,但还占用系统资源,要避免僵尸态的产生
进程状态切换图
进程创建后,进程进入就绪态,当CPU调度到此进程时进入运行态,当时间片用完时,此进程会进入就绪态,如果此进程正在执行一些IO操作(阻塞操作)会进入阻塞态,完成IO操作(阻塞结束)后又可进入就绪态,等待CPU的调度,当进程运行结束即进入结束态。
就绪状态
当进程已分配到除CPU以外的所有必要的资源,只要获得处理机便可立即执行,这时的进程状态称为就绪状态。
执行状态
当进程已获得处理机(CPU),其程序正在处理机上执行,此时的进程状态称为执行状态。
阻塞状态
正在执行的进程,由于等待某个事件发生而无法执行时,便放弃处理机而处于阻塞状态。例如,等待I/O完成、申请缓冲区不能满足、等待信件(信号)等。