linux系统编程01-文件系统

介绍

类ls的实现,如myls, -l -a -i -n

一、目录和文件

二、系统数据文件和信息

三、进程环境

参考书籍:apuecsapp

一、目录和文件

linux系统编程01-文件系统

1. 获取文件的属性 : stat

##include <sys/types.h> ##include <sys/stat.h> ##include <unistd.h>  int stat(const char *pathname, struct stat *statbuf); int fstat(int fd, struct stat *statbuf); int lstat(const char *pathname, struct stat *statbuf); 
  • 参数: 路径,结构体地址,用来填充文件信息
  • 返回值:成功0,失败-1
  • 区分:
    • stat 用路径获取文件属性,面对符号链接时获取的是目标文件的属性
    • fstatfd 获取文件属性,同上
    • lstatfd 获取文件属性,面对符号链接时,获取的符号链接的属性

struct stat 的内容: man 2 stat 查看

linux系统编程01-文件系统

主要包括 inodest_sizeuidgid。 命令 lsstat 的内容都是从中拿取的。

例子:用 stat 函数统计文件大小

示例代码:

##include<stdio.h> ##include<stdlib.h> ##include<sys/types.h> ##include<sys/stat.h> ##include<unistd.h>  static off_t flen(const char *FNAME) {     struct stat statres;     if(stat(FNAME, &statres) < 0)     {            perror("stat()");         exit(1);     }        return statres.st_size; }  int main(int argc, char **argv) {     if(argc < 2)     {            fprintf(stderr, "Usage():...n");         exit(1);     }         printf("%lldn",(long long)flen(argv[1])); 		exit(0); } 

运行结果:

linux系统编程01-文件系统

注意: st_size 的属性是 off_t ,大小取决于机器的架构,有的是longlong,有的是int。所以 1. 可以强转为longlong 2.在 makefile 里加 CFLAGS += -D_FILE_OFFSET_BITS=64

文件的 st_size 只是一个文件属性, 而 blocks 才是真正占用的磁盘大小

示例代码

##include<stdio.h>       ##include<stdlib.h> ##include<sys/types.h> ##include<sys/stat.h> ##include<unistd.h> ##include<fcntl.h>  int main(int argc, char ** argv) {     if(argc < 2)     {         fprintf(stderr, "Usagne:...n");         exit(1);     }     int fd;     fd = open(argv[1], O_WRONLY|O_CREAT|O_TRUNC, 0600);     if(fd < 0)     {         perror("open()");         exit(1);     }     if(lseek(fd, 5*1024*1024*1024LL-1LL, SEEK_SET) < 0)     {         perror("lseek()");         exit(1);     } } 

运行结果:

linux系统编程01-文件系统

程序解释:

  • 所有的常量都有单位, 没写单位则默认, lseek(fd, 5*1024*1024*1024LL-1LL, SEEK_SET) 此处如果不加上 LL 则默认是 int ,那么就会爆
  • 运行结果说明:s
    • size为5G大小的文件实际占用的磁盘大小为4KB。
    • cp 发现是空洞内容就不会进行实际的 write 所以虽然两个文件的 size 一样,但是第二个文件的 blocks 为0,实际上不占用磁盘空间。因此出现 siz=5G但不占用磁盘空间。
    • 二者都表明unix中 size 只是一个文件属性,而不是表示文件大小,这一点要和 windows区分开。
  • 当前内核运行结果:

linux系统编程01-文件系统

名词 解析 一般大小
size 文件的大小,是文件的属性 /
扇区 磁盘划分的单位,存储的最小单元 512B(0.5KB)
块block 文件io的最小单元 4096B(4KB = 8*扇区)

即使存储1KB文件,也要占用一个块(4KB),读取时也是一个块一个块地读(cache)

https://blog.csdn.net/daiyudong2020/article/details/53897775

因此,对于 flen.c ,虽然只有496B,但是也要占用4KB的磁盘空间。( stat 的blocks的单位是扇区大小,可以推测 blocks ≥ 8

2.文件属性

stat函数中 st_mode :一个16位的位图,用于表示文件类型,文件访问权限,以及特殊权限位。

16 ⇒ 7种文件类型(3bit) + 文件访问权限(rwx*3=9bit) + 特殊权限位(uid+gid+sticky=3) = 15

七种文件类型: dcb-lsp 目录、字符设备、块设备、常规文件、符号链接、网络socket、管道

下面函数是使用宏实现的, 判断文件类型, 函数返回真假以表明是否属于这种文件类型

linux系统编程01-文件系统

linux系统编程01-文件系统

例子:写程序判断文件类型

示例代码:

##include<stdio.h>   ##include<stdlib.h> ##include<sys/types.h> ##include<sys/stat.h> ##include<unistd.h> ##include<fcntl.h>  static char* ftype(const char *FNAME) {        struct stat statres;     if(stat(FNAME, &statres) < 0)     {            perror("stat()");         exit(1);     }          if(S_ISREG(statres.st_mode))         return "regular file";     else         return "not regular file"; }  int main(int argc, char **argv) {     if(argc < 2) 		{         fprintf(stderr, "Usage:...n");         exit(1);     }      printf("%sn",ftype(argv[1]));      exit(0); } 

运行结果:

linux系统编程01-文件系统

3.umask

作用:避免产生权限过松的文件

文件权限 = 0664 & ~umask

命令 umask 是由函数 umask 封装而成,程序中可以使用函数 umask 来改变umask

4.文件权限管理

命令 chmod

  • chmod 666 file_name :直接改变文件权限
  • chomod ugo+rwx :加减文件权限

函数 chomod 用法类似:

int chmod(const char *pathname, mode_t mode); int fchmod(int fd, mode_t mode); 

5.粘住位

现在用的越来越少,仅做了解

作用:一开始是为了让可执行文件的装载内容在内存中保留,下次调用的时候装载得更快,但现在已经有page cache机制,所以不那么常用

现在一般是给目录设置t位,如 /tmp

linux系统编程01-文件系统

6.文件系统:FAT、UFS

FAT文件系统:

linux系统编程01-文件系统

静态单链表可以写为:【算法基础课里的写法】

struct node{ 	int next; //下一个的下标 	char data[SIZE]; //数据 }nodes[N]; 

也可以写为上述的形式。

可见:FAT文件系统的承载能力取决于N,惧怕大文件;而且由于是单链表,单向索引,所以取数据不灵活。

UFS文件系统:

linux系统编程01-文件系统

linux系统编程01-文件系统

  • inode 是一个结构体,存储文件相关信息(stat命令就是从这里取的),和一个指针数组(12+3),分别指向11个直接数据块,1个一、二、三级间接数据,存的是数据块的物理地址。所以一个文件对应一个 inodeinode 的指针数组整合了所有数据块,没有链式结构了,并且不怕大文件了。
  • inode位图块位图 用来表示某一个 inode 或者某一个块有没有被使用

linux系统编程01-文件系统

  • 目录文件就是一个文件,没有什么特殊
  • 只不过它的文件块中存储的数据是目录项 inode - filename 的对应关系
  • 路径解析:
    • 前提:知道 / 目录的数据块,这是周知的,操作系统初始化时就做好,在 inode位图 里的第二位。
    • 解析 /tmp/out :根据 / 的inode得到 / 目录文件的数据块,里面的内容是数据项, 包含 out文件名和它对应的inode,在根据 out文件的inode,就可以得到out文件的数据块。

7.硬链接,符号链接

软硬链接:

ln 内部用 link函数实现, 对应的是 unlink 函数 【 man 2 link/unlink

unlink实现匿名函数: open 后再 unlink

unlink 封装出命令 rm 和库函数( man 3 )函数 remove 【unlink是系统调用,移植性不够好】

asd

其他:

文件移动和重命名: rename → 封装出命令 mv

时间: utime

用以更改 Acess time 和 modify time

9. 文件目录解析 : glob

  • 创建删除: mkdir rmdir
  • 更改路径: chdir fchdir → 封装出命令 mv
  • 获取当前路径: getcwd → 封装出命令 pwd

关于main的命令行参数:

示例代码:

##include<stdio.h> ##include<stdlib.h>  int main(int argc, char **argv) {     int i;     for(i=0; argv[i] != NULL; i++)         puts(argv[i]);       exit(0); } 

运行结果:

linux系统编程01-文件系统

几点说明:

  • argv 数组是以 NULL 结尾的
  • 终端执行 ./main *c 是可以匹配通配符,是因为 main 函数的参数支持通配符匹配吗,并不是。是因为 *.c 是经过 终端shell 再到程序的,是shell把通配符匹配掉了

读取和分析目录:

##include <glob.h> glob();  //把目录操作视为流操作 opendir(); closedir(); readdir(); seekdir(); telldir(); 

glob函数:

int glob(const char *pattern, int flags,                 int (*errfunc) (const char *epath, int eerrno),                 glob_t *pglob); 
  • 参数:

    • pattern 模式串,支持通配符

    • flags 标志选项: GLOB_NOCHECK GLOB_NOSORT GLOB_APPEND

    • errfunc 函数指针:用来处理错误信息

    • pglob 结构体,反填结果

      • gl_pathcgl_pathv 的结构和用法和 argcargv 一样

      linux系统编程01-文件系统

  • 返回值:成功返回0,失败返回1

例子:列出 /etc 目录下a开头的.conf文件

示例代码:

##include<stdio.h> ##include<stdlib.h> ##include<glob.h>  ##define PAT "/etc/a*.conf"  int main() {     int i,err;     glob_t globres;      err = glob(PAT, 0, NULL, &globres);     if(err)     {            printf("Error code = %dn", err);         exit(1);     }         for(i=0; i < globres.gl_pathc; i++)         puts(globres.gl_pathv[i]);           exit(0); } 

运行结果:

linux系统编程01-文件系统

说明

  • 为什么 glob 出错时不用 perror ,因为 glob 不会置 errno

  • 错误处理函数

    linux系统编程01-文件系统

目录流函数:

##include <sys/types.h> ##include <dirent.h>  DIR *opendir(const char *name); DIR *fdopendir(int fd); int closedir(DIR *dirp);  struct dirent *readdir(DIR *dirp); 

可见和流操作很像,只不过捏的不是 FILE 而是 DIR

linux系统编程01-文件系统

例子:列出 /etc 目录下所有文件

示例代码:

##include<stdio.h> ##include<stdlib.h> ##include<sys/types.h> ##include<dirent.h>  ##define PAT "/etc"     int main() {     DIR * dp;      struct dirent *cur;      dp = opendir(PAT);     if(dp == NULL)     {            //会置errno         perror("opendir()");         exit(1);     }         while((cur = readdir(dp)) != NULL)         puts(cur->d_name);      closedir(dp);      exit(0); } 

运行结果:

linux系统编程01-文件系统

例子:实现指令 du

指令 du 以KB的形式返回 文件或目录 所占用的大小

示例代码:

##include<stdio.h> ##include<stdlib.h> ##include<sys/types.h> ##include<sys/stat.h> ##include<unistd.h> ##include<glob.h> ##include<string.h>  ##define PATHSIZE 1024  static int path_noloop(const char *path) {     char *pos;     pos = strrchr(path, '/');      if(pos == NULL)         exit(1);     if( strcmp(pos+1, ".") == 0 || strcmp(pos+1, "..") == 0)          return 0;      return 1; }  static int64_t mydu(const char *path) {     struct stat statres;     glob_t globres;     int err,i;     int64_t sum;     char nextpath[PATHSIZE];      //使用lstat     if(lstat(path, &statres) < 0)     {         perror("stat()");         exit(1);     }      //非目录     if(!S_ISDIR(statres.st_mode))         return statres.st_blocks;      //目录文件:递归处理     //拼接路径     strncpy(nextpath, path, PATHSIZE);     strncat(nextpath, "/*", PATHSIZE-1);     glob(nextpath, 0, NULL, &globres);     /*if(err)     {         fprintf(stderr, "glob():errcode = %dn", err);         exit(1);     }*/           strncpy(nextpath, path, PATHSIZE);     strncat(nextpath, "/.*", PATHSIZE-1);     glob(nextpath, GLOB_APPEND, NULL, &globres); //追加方式     /*if(err)     {         fprintf(stderr, "glob():errcode = %dn", err);         exit(1);     }     */          sum = statres.st_blocks; //算上目录文件本身的大小     //目录下所有文件的大小     for(i=0; i<globres.gl_pathc; i++)     {         if(path_noloop(globres.gl_pathv[i]))             sum += mydu(globres.gl_pathv[i]);     }      globfree(&globres); //释放空间     return sum;       }  int main(int argc, char **argv) {     if(argc < 2)     {         fprintf(stderr, "Usage:...n");         exit(1);     }      printf("%ldt%sn",mydu(argv[1])/2, argv[1]);      exit(0); } 

运行结果:

linux系统编程01-文件系统

注意点:

  • 不知道为什么 glob 一校验就出错,所以放弃了校验; /* 表示路径下所有文件,不包括隐藏文件,所以分两步
  • strncat 的为 PATHSIZE会报警告,所以-1
  • 常用字符串函数: strncpy strcmp strncat (追加) strrchr 找到某字符最右边的出现位置

二、系统数据文件和信息

linux系统编程01-文件系统

1. 用户信息:/etc/passwd

root 用户才有查看权限

用户信息不能从文件中直接拿,因为不同的系统记录用户数据的方式不同

标准出来和稀泥,规定两个函数:

struct passwd *getpwnam(const char *name); struct passwd *getpwuid(uid_t uid) 

linux系统编程01-文件系统

例子:输入uid,得到unam

示例代码:

##include<stdlib.h> ##include<stdio.h> ##include<sys/types.h> ##include<pwd.h>  int main(int argc, char **argv) {         struct passwd *pwdline;          if(argc < 2)         {                 fprintf(stderr, "Usage:...n");                 exit(1);         }          pwdline = getpwuid(atoi(argv[1]));          puts(pwdline->pw_name);          exit(1); } 

运行结果:

linux系统编程01-文件系统

2. 组信息: /etc/group

两个函数,用法同上

struct group *getgrnam(const char *name); struct group *getgrgid(gid_t gid); 

3. 加密: /etc/shadow

##include <shadow.h> struct spwd *getspnam(const char *name); //通过用户名得到 shadow文件中的一行  ##include <crypt.h> **链接的时候加这句:-lcrypt** char *crypt(const char *phrase, const char *setting); //将phrase和杂质串setting加密,返回加密后的串  ##include <unistd.h> char *getpass(const char *prompt); //关闭终端回显功能,输入内容,再打开回显,返回输入的内容 //prompt是提示信息 

linux系统编程01-文件系统

linux系统编程01-文件系统

makefile:crypt链接

例子:写一个 check-pass, 用户输入用户名和密码,判断是否正确

思路:

  • 用户输入用户名,用户名通过 getnam 拿到 shadowline 的一行
  • 用户输入密码,密码通过 crypt 拿到用户输入密码加密后的密文
  • shadowline 中的密文和用户输入密码加密后的密文比较,相等则成功,否则失败

示例代码:

##include<crypt.h> ##include<unistd.h> ##include<string.h>  int main(int argc, char **argv) {         char *input_pass;         struct spwd *shadowline;         char *crypted_pass;          if(argc < 2)         {                 fprintf(stderr, "Usage:...n");                 exit(1);         }          input_pass = getpass("Password:");          shadowline = getspnam(argv[1]);          crypted_pass = crypt(input_pass, shadowline->sp_pwdp);          if(strcmp(crypted_pass, shadowline->sp_pwdp) == 0)                 puts("ok");         else puts("fail");          exit(0); } 

运行结果:

linux系统编程01-文件系统

注意点:不知为何修改 makefile 没有作用,所以手动加上了;要用root执行,否则没有权限访问 /etc/shadow,会报 段错误

4. 时间函数

围绕三种数据类型:

  • time_t :大整数,计算机喜欢
  • struct tm :结构体,程序员喜欢
  • char * :字符串,用户喜欢

linux系统编程01-文件系统

涉及到的函数:

##include <time.h> //拿到大整数 time_t time(time_t *tloc)  //大整数转结构体 struct tm *gmtime(const time_t *timep); //格林威治时间 struct tm *localtime(const time_t *timep); //本地时间  //结构体转字符串 size_t strftime(char *s, size_t max, const char *format,                        const struct tm *tm);  //结构体转大整数:参数没有const修饰,会调整tm为合法 time_t mktime(struct tm *tm); 
  • gmtime | localtime :结果指针在静态区,所以结果要马上用,否则会被冲掉

  • 结构体成员

    linux系统编程01-文件系统

例子:编写 timelog.c 输出行号,时间戳,追加输入

示例代码:

##include<stdio.h> ##include<stdlib.h> ##include<time.h> ##include<unistd.h>  ##define FNAME "/tmp/out"  int main() {     FILE *fp;     int cnt=0;     size_t linesize;     char *timestr;     time_t stamp;     struct tm *tm;      fp = fopen(FNAME, "a+");       if(fp == NULL)     {            perror("fopen()");         exit(1);     }         timestr = NULL;     linesize = 0;     while(getline(&timestr, &linesize, fp) > 0) 				cnt++;          while(1)     {         time(&stamp);         tm = localtime(&stamp);         fprintf(fp, "%-4d: %d-%d-%d %d:%d:%dn", ++cnt,                 tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday,                 tm->tm_hour, tm->tm_min, tm->tm_sec);         fflush(fp);         sleep(1);     }        fclose(fp);      exit(0); } 

运行结果:

linux系统编程01-文件系统

注意点:

  • 进程被杀死后没有关闭文件:可控的内存泄漏,之后用钩子函数
  • 处理中断,都是全缓冲,要 fflush 否则看不到输出

例子: 100days.c :查看100天后的日期

示例代码:

##include<stdio.h> ##include<stdlib.h> ##include<time.h>  ##define TIMESTRSIZE 1024  int main() {     char timestr[TIMESTRSIZE];     time_t stamp;     struct tm *tm;      time(&stamp);     tm = localtime(&stamp); 		//各种格式参数查手册     strftime(timestr, TIMESTRSIZE, "Now: %Y-%m-%d", tm);     puts(timestr);      tm->tm_mday += 100;     mktime(tm);  //利用mktime副作用修正tm     strftime(timestr, TIMESTRSIZE, "After 100 days: %Y-%m-%d", tm);       puts(timestr);      exit(0); } 

运行结果:

linux系统编程01-文件系统

三、 进程环境

linux系统编程01-文件系统

1. main函数

程序的入口与出口,一个程序有且仅有一个

2. 进程的终止

背过: Very Important!

linux系统编程01-文件系统

exit、_exit、_Exit

  • 三者的返回值都是给父进程看。shell运行程序后可用 echo $? 查看

    实际返回的状态数不是 int :保留低八位,有符号 char -128 ~ +127

    linux系统编程01-文件系统

  • exit 是库函数,其他是系统调用。
    exit :先清理现场,调用钩子函数等,后利用 _exit 退出
    _exit :直接退出

    linux系统编程01-文件系统

    exit手册说明

    linux系统编程01-文件系统

  • 何时用 _exit :遇到重大故障,防止故障扩散。
    [func只会返回012,但是现在返回了其他值,有理由认为发生了覆盖写,为了防止错误数据扩散,要立即退出,查看错误现场]

    linux系统编程01-文件系统

钩子函数

执行 exit 之前被逆序调用,像被钩上来一样。作用类似于 析构函数。

int atexit(void (*function)(void)); 

例子:演示钩子函数调用时机和顺序

示例代码:

##include<stdio.h> ##include<stdlib.h>  void f1(void) {     puts("f1 is working"); } void f2(void) {     puts("f2 is working"); } void f3(void) {     puts("f3 is working"); }  int main() {       puts("Begin");      atexit(f1);     atexit(f2);     atexit(f3);      puts("End");     exit(0); } 

运行结果:

linux系统编程01-文件系统

具体的例子 : 释放打开的文件或其他需要逆操作的资源

不写钩子函数,代码体量会越来越大

linux系统编程01-文件系统

linux系统编程01-文件系统

钩子函数即可解决此问题,打开某一个文件后,立刻调用钩子函数。这样在进程正常结束前,就会调用钩子函数释放资源:

linux系统编程01-文件系统

3. 命令行参数分析

##include <unistd.h>  int getopt(int argc, char * const argv[], 	        const char *optstring); //关联的全局变量 extern char *optarg; extern int optind, opterr, optopt; 
  • 参数
    • argc argv 就是命令行参数
    • optstring 识别的选项
      • 前面加 - :表示处理非选项,如 ls -a /tmp/out 中的 /tmp/out
      • 选项后加 : :表示该选项有参数
  • 返回值
    • 读取完: -1
    • 成功:为选项→选项字符;非选项→1
  • 关联的全局变量
    • optarg :如果选项有参数,指向该参数
    • optind :index,当前在解析第几个参数,用的时候减1表示当前参数

getopt_long():分析长格式 如 ls --all

例子:mydate.c

示例代码:

##include<stdio.h> ##include<stdlib.h> ##include<time.h> ##include<unistd.h> ##include<string.h>  ##define TIMESTRSIZE 1024 ##define STROPTSIZE  1024  int main(int argc, char **argv) {     char timestr[TIMESTRSIZE];     char stropt[STROPTSIZE];     time_t stamp;     struct tm *tm;     int c;     FILE *fp = stdout;            time(&stamp);     tm = localtime(&stamp);          //先初始化为空串,再往里追加     stropt[0] = '';     while(1)     {         c = getopt(argc, argv, "-H:MSy:md");         if(c < 0) break;         switch(c)         {             /*case 1:                  fp = fopen(argv[optind-1], "w");                  if(fp == NULL)                  {                      perror("fopen()");                      //文件打开失败则写往终端                      fp = stdout;                  }                  break;*/             case 'H':                  if(strcmp("12", optarg) == 0)                     strncat(stropt, "%I(%P) ", STROPTSIZE-1);                  else if(strcmp("24", optarg) == 0)                     strncat(stropt,"%H ", STROPTSIZE-1);                  else                      fprintf(stderr, "Invalid argument of -Hn");                  break;             case 'M':                  strncat(stropt,"%M ", STROPTSIZE-1);                  break;             case 'S':                  strncat(stropt,"%S ", STROPTSIZE-1);                  break;             case 'y':                  if(strcmp("2", optarg) == 0)                     strncat(stropt,"%y ", STROPTSIZE-1);                  else if(strcmp("4", optarg) == 0)                      strncat(stropt,"%Y ", STROPTSIZE-1);                  else                      fprintf(stderr, "Invalid argument of -yn");                  break;             case 'm':                  strncat(stropt,"%m ", STROPTSIZE-1);                  break;             case 'd':                  strncat(stropt,"%d ", STROPTSIZE-1);                  break;             default:                  break;         }     }      strncat(stropt, "n", TIMESTRSIZE-1);     strftime(timestr, TIMESTRSIZE, stropt, tm);     fputs(timestr, fp);      //非标准输出才关闭,否则会关闭标准输出     if(fp != stdout)         fclose(fp);     exit(0); } 

运行结果:

linux系统编程01-文件系统

未实现的功能:解析非选项参数:指定日期的输出位置。 如 ./mydate -y 4 /tmp/out 表示把年份输入到 /tmp/out 文件中

【视频42】

4. 环境变量

本质:Key = Value

char *getenv(const char *name);  int setenv(const char *name, const char *value, int overwrite); int putenv(char *string); 
  • getenv() :提供键,返回值。 例子: puts(getenv("PATH"))
  • setenv() :添加或修改键值对
    • overwrite==1 :键已存在,覆盖写
    • overwrite==0 :键已存在,不覆盖写
  • putenv() :添加或修改键值对,不推荐使用,因为参数没有const修饰,可能会被改变

注意: 覆盖写的时候是情况原来的空间,然后转移到堆存储新的键值对。如果不这么做,如果修改后的值所占空间比原来的大,就无法存储。

其他:

export :命令,查看环境变量

environ :全局变量数组,类似于argv

linux系统编程01-文件系统

5. C程序的存储空间和库

存储空间分布:从下到上: 代码段、为初始化的数据段、初始化的数据段、堆、其他、栈、argcargv。堆和栈的空间可以变动。

3G以上是内核信息

linux系统编程01-文件系统

命令 pmap :查看一个程序的空间:

编一个程序,getchar等待输入,然后另开一个终端 ps axf 查看进程号,然后执行 pmap

linux系统编程01-文件系统

库:

linux系统编程01-文件系统

手册example。注意使用上述函数的时候要 Link with -ldl.

linux系统编程01-文件系统

6. setjmplongjmp

  • goto 函数的必要性

    查找有1000层的数的某个结点,没有改变函数空间,那么可以goto快速返回;C++异常抛出机制

    经过复杂步骤进来,且没有改变空间,就可以goto快速返回

    linux系统编程01-文件系统

    goto不能实现跨函数跳转,因为现场没有切换。

    setjmp 和 longjmp 解决了这个问题。安全地跨函数跳转,被称为长返回,长跳转。

##include <setjmp.h> int setjmp(jmp_buf env); void longjmp(jmp_buf env, int val); 
  • setjmp 返回值类似fork,后面加分支:如果顺次执行,返回0,跳转回来则返回携带的值。
  • longjmp 第二个参数带回0,会被替换为1,防止死循环

例子:跨函数跳转

示例代码:

##include<stdio.h> ##include<stdlib.h> ##include<setjmp.h>  jmp_buf save;  void c(void) {     printf("%s():Begin.n", __FUNCTION__);     longjmp(save, 6);     printf("%s():End.n", __FUNCTION__); }  void b(void) {     printf("%s():Begin.n", __FUNCTION__);     printf("%s():Call c()n", __FUNCTION__);     c();     printf("%s():Return from c()n",__FUNCTION__);     printf("%s():End.n", __FUNCTION__); }  void a(void) {     printf("%s():Begin.n", __FUNCTION__);     printf("%s():Call b()n", __FUNCTION__);     b();     printf("%s():Return from b()n",__FUNCTION__);     printf("%s():End.n", __FUNCTION__); }  int main() {     int ret;     printf("%s():Begin.n", __FUNCTION__);     ret = setjmp(save);     if(ret == 0)     {         printf("%s():Call a()n", __FUNCTION__);         a();         printf("%s():Return from a()n",__FUNCTION__);     }     else     {         printf("%s(): Jmp back here with code: %dn", __FUNCTION__, ret);     }     printf("%s():End.n", __FUNCTION__);     exit(0); } 

运行结果:

linux系统编程01-文件系统

没跳转

linux系统编程01-文件系统

跳转【运行结果】

7. 资源获取及控制

命令 ulimit 用下面两个函数实现:

linux系统编程01-文件系统

linux系统编程01-文件系统

  • 软限制小于等于硬限制
  • 普通用户不能提高硬限制, root可以
发表评论

评论已关闭。

相关文章

当前内容话题