8.2 低级IO read/write 利用这个系统调用来构造高级一点的函数, 库函数之类的
系统调用的函数原型集中放在一个头文件syscalls.h中( 事实上目前的系统里只有syscall.h,最后也会调用unistd.h)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 #include <stdio.h> #include <unistd.h> int main () { char buf[BUFSIZ]; int n; while ((n = read(0 , buf, BUFSIZ)) > 0 ) write(1 , buf,n); return 0 ; }
1 2 3 4 io.c:3 :10 : fatal error: syscalls.h: No such file or directory 3 | #include "syscalls.h" | ^~~~~~~~~~~~ compilation terminated.
https://blog.csdn.net/sesiria/article/details/52337114
PS: /usr/include/目录下存着c的各种头文件,可以从这里寻找
1 2 # cat /usr/include/syscall.h# include <sys/syscall.h>
确实是存在这个目录的,但是为什么没找到呢? syscall.h, 没有s
1 2 #include "syscall.h" #include <stdio.h>
实现getchar(无缓冲区)
1 2 3 4 5 6 7 #include "syscalls.h" int getchar (void ) { char c; return (read(0 ,&c,1 ) == 1 ) ? (unsigned char ) c: EOF; }
第二版 一次读入一组字符,但每次只输出一个字符(简单的带缓冲区 的版本)
但是这个函数调用完了,缓冲区什么的也都没了吧?? 不是的, static的生命周期,在整个程序的运行期间都存在
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 #include <stdio.h> #include <unistd.h> int getchar (void ) ;int main () { char s; while ((s = getchar())!=EOF){ write(1 ,&s,1 ); } } int getchar (void ) { static char buf[BUFSIZ]; static char *bufp = buf; static int n = 0 ; if (n == 0 ){ n = read(0 ,buf, sizeof buf); bufp = buf; } return (--n>0 ) ? (unsigned char ) *bufp++ : EOF; }
8.3 open、creat、close和unlink 1 2 3 4 5 6 #include <fcntl.h> int fd;int open (char *name,int flags,int perms) ;fd = open(name, flags, perms)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 #include <stdio.h> #include <unistd.h> #include <fcntl.h> #include <stdarg.h> #include <stdlib.h> #define PERMS 0666 void error (char *,...) ;int main (int argc, char *argv[]) { int f1,f2,n; char buf[BUFSIZ]; if (argc != 3 ) error("Usage: cp from to" ); if ((f1 = open(argv[1 ],O_RDONLY,0 )) == -1 ) error("cp: can't open %s" ,argv[1 ]); if ((f2 = creat(argv[2 ],PERMS)) == -1 ) error("cp: can't create %s,mode %03o" ,argv[2 ],PERMS); while ((n = read(f1,buf,BUFSIZ)) > 0 ) if (write(f2,buf,n) !=n) error("cp: write error on file %s" ,argv[2 ]); return 0 ; } void error (char *fmt,...) { va_list args; va_start(args,fmt); fprintf (stderr ,"error: " ); vfprintf (stderr ,fmt,args); fprintf (stderr ,"\n" ); va_end(args); exit (1 ); }
8.5 fopen与getc函数的实现 给的iobuf应该是dos的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 #include <fcntl.h> #include "syscalls.h" #define PERMS 0666 FILE *fopen (char *name, char *mode) { int fd; FILE *fp; if (*mode != 'r' && *mode !='w' && *mode!='a' ) return NULL ; for (fp= _iob; fp < _iob + OPEN_MAX; fp++) if ((fp->flag & (_READ | _WRITE)) == 0 ) break ; if (fp > _iob+OPEN_MAX) return NULL ; if (*mode == 'w' ) fd = creat(name,PERMS); else if (*mode == 'a' ){ if ((fd = open(name,O_WRONLY,0 )) == -1 ) fd = creat(name,PERMS); lseek(fd,0L ,2 ); }else fd = open(name,O_RDONLY,0 ); if (fd == -1 ) return NULL ; fp->fd = fd; fd->cnt =0 ; fp->base = NULL ; fp->flag = (*mode == 'r' ) ? _READ : _WRITE; return fp; } int _fillbuf(FILE *fp){ int bufsize; if ((fp->flag&(_READ|_EOF|_ERR)) != _READ) return EOF: bufsize = (fp->flag & _UNBUF) ? 1 : BUFSIZE; if (fp->base == NULL ) if ((fp->base = (char *) malloc (bufsize)) == NULL ) return EOF; fp->ptr = fp->base; fp->cnt = read(fp->fd, fp->ptr,bufsize); if (--fp->cnt < 0 ){ if (fp->cnt == -1 ) fp->flag |= _EOF; else fp->flag !=_ERR: fp->cnt = 0 ; return EOF: } return (unsigned char ) *fp->ptr++; }
8.6 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 #define NAME_MAX 14 typedef struct { long ino; char name[NAME_MAX+1 ]; } Dirent; typedef struct { int fd; Dirent d; } DIR1; DIR1 *opendir1 (char *dirname) ; Dirent *readdir1 (DIR1 *dfd) ; void closedir1 (DIR1 *dfd) ;#include <stdio.h> #include <string.h> #include <fcntl.h> #include <sys/types.h> #include <sys/stat.h> #include <stdlib.h> #include <unistd.h> void fsize (char *) ;void dirwalk (char *, void (*fcn)(char *)) ;int main (int argc, char **argv) { if (argc == 1 ) fsize("." ); else while (--argc > 0 ) fsize(*++argv); return 0 ; } void fsize (char *name) { struct stat stbuf ; if (stat(name,&stbuf) == -1 ) { fprintf (stderr ,"fsize: can't access %s\n" ,name); } if ((stbuf.st_mode & S_IFMT) == S_IFDIR) { printf ("is a dir\n" ); dirwalk(name, fsize); } printf ("%8ld %s\n" ,stbuf.st_size,name); } #define MAX_PATH 1024 void dirwalk (char *dir,void (*fcn)(char *)) { char name[MAX_PATH]; Dirent *dp; DIR1 *dfd; if ((dfd = opendir1(dir)) == NULL ) { fprintf (stderr ,"dirwalk: can't open %s\n" ,dir); return ; } printf ("here\n" ); while ((dp = readdir1(dfd)) != NULL ){ printf ("dp->name:%s" ,dp->name); if (strcmp (dp->name,"." ) ==0 || strcmp (dp->name,".." )==0 ) continue ; if (strlen (dir)+strlen (dp->name)+2 > sizeof (name)) fprintf (stderr ,"dirwalk: name %s/%s too long\n" ,dir,dp->name); else { sprintf (name,"%s/%s" ,dir,dp->name); (*fcn)(name); } } closedir1(dfd); } DIR1 *opendir1 (char *dirname) { int fd; struct stat stbuf ; DIR1 *dp; if ((fd = open(dirname,0 ,O_RDONLY,0 )) == -1 || fstat(fd,&stbuf) == -1 || (dp = (DIR1 *) malloc (sizeof (DIR1))) == NULL ) return NULL ; dp->fd = fd; return dp; } #include <sys/dir.h> #ifndef DIRSIZ #define DIRSIZ 14 #endif struct direct1 { ino_t d_ino; char d_name[DIRSIZ]; }; Dirent *readdir1 (DIR1 *dp) { struct direct1 dirbuf ; static Dirent d; while (read(dp->fd,(char *)&dirbuf,sizeof (dirbuf)) == sizeof (dirbuf)){ if (dirbuf.d_ino == 0 ) continue ; d.ino = dirbuf.d_ino; strncpy (d.name, dirbuf.d_name,DIRSIZ); d.name[DIRSIZ] = '\0' ; return &d; } return NULL ; } void closedir1 (DIR1 *dp) { if (dp){ close(dp->fd); free (dp); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 #define NAME_MAX 14 #include <stdio.h> #include <string.h> #include <fcntl.h> #include <sys/types.h> #include <sys/stat.h> #include <stdlib.h> #include <unistd.h> #include <sys/dir.h> #define MAX_PATH 1024 void dirwalk (char *dir,void (*fcn)(char *)) { char name[MAX_PATH]; struct dirent *dp ; DIR *dfd; if ((dfd = opendir(dir)) == NULL ) { fprintf (stderr ,"dirwalk: can't open %s\n" ,dir); return ; } while ((dp = readdir(dfd)) != NULL ){ if (strcmp (dp->d_name,"." ) ==0 || strcmp (dp->d_name,".." )==0 ) continue ; if (strlen (dir)+strlen (dp->d_name)+2 > sizeof (name)) fprintf (stderr ,"dirwalk: name %s/%s too long\n" ,dir,dp->d_name); else { sprintf (name,"%s/%s" ,dir,dp->d_name); (*fcn)(name); } } closedir(dfd); } void fsize (char *name) { struct stat stbuf ; if (stat(name,&stbuf) == -1 ) { fprintf (stderr ,"fsize: can't access %s\n" ,name); } if ((stbuf.st_mode & S_IFMT) == S_IFDIR) { dirwalk(name, fsize); } printf ("%8ld %s\n" ,stbuf.st_size,name); } int main (int argc, char **argv) { if (argc == 1 ) fsize("." ); else while (--argc > 0 ) fsize(*++argv); return 0 ; }
其实那些opendir函数等都不需要自己实现(不过从练习的角度讲,可以自己实现) , 自己实现的话,记得要根据操作系统的情况, 把对应的结构体都修改了,否则就会出问题
https://github.com/Heatwave/The-C-Programming-Language-2nd-Edition/tree/master/chapter-8-the-unix-system-interface
https://www.learntosolveit.com/cprogramming/chapter8/ex_8.5_fsize
niubi: https://stackoverflow.com/questions/7381000/what-is-wrong-with-this-example-from-kr
8.7 存储分配程序实例 内存抽象成块的组织形式,以链表的形式进行组织,每个块都含有一个长度、指向下一个块的指针以及一个指向自身数据存储位置的指针.
1 2 3 4 5 6 7 8 9 10 11 typedef long Align; union header { struct { union header *ptr ; unsigned size; } s; Align x; }; typedef union header Header ;
malloc时, ,找到的块太大的话,把尾部返回给用户,这样,初始块的头部只需要修改size就可以了
free时,寻找的首先是这样的情况, bp > p && bp < p->s.ptr
如果不符合,看是否符合这种情况,即被释放的块在链表的开头或者末尾
最终代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 #include <stddef.h> #include <string.h> typedef long Align; union header { struct { union header *ptr ; unsigned size; } s; Align x; }; typedef union header Header ;static Header base; static Header *freep = NULL ; void *malloc (unsigned nbytes) { Header *p,*prevp; Header *morecore (unsigned ) ; unsigned nunits; nunits = (nbytes+sizeof (Header)-1 )/sizeof (Header)+1 ; if ((prevp=freep) == NULL ){ base.s.ptr = freep = prevp = &base; base.s.size= 0 ; } for (p = prevp->s.ptr; ;prevp=p,p = p->s.ptr){ if (p->s.size > nunits){ if (p->s.size == nunits) prevp->s.ptr = p->s.ptr; else { p->s.size = p->s.size - nunits; p += p->s.size; p ->s.size = nunits; } freep = prevp; return (void *)(p+1 ); } if (p == freep) if ((p = morecore(nunits)) == NULL ) return NULL ; } } void free (void *ap) { Header *bp, *p; bp = (Header *)ap - 1 ; for (p = freep; !(bp > p && bp < p->s.ptr); p = p->s.ptr) if (p >= p->s.ptr && (bp > p || bp < p->s.ptr)) break ; if ( bp + bp->s.size == p->s.ptr){ bp->s.size += p->s.ptr->s.size; bp->s.ptr = p->s.ptr->s.ptr; } else bp->s.ptr = p->s.ptr; if (p + p->s.size == bp){ p->s.size += bp->s.size; p->s.ptr = bp->s.ptr; } else p->s.ptr = bp; freep = p; } #define NALLOC 1024 Header *morecore (unsigned nu) { char *cp, *sbrk(int ); Header *up; if (nu < NALLOC) nu = NALLOC; cp = sbrk(nu * sizeof (Header)); if (cp == (char *) -1 ) return NULL ; up = (Header *) cp; up->s.size = nu; free ((void * )(up+1 )); return freep; } void main () { char *str1; char *str2; str1 = malloc (0x20 ); strcpy (str1, "hello" ); str2 = malloc (0x30 ); strcpy (str2, "tang" ); }