参考站点
使用的shell命令
ls -l
grep -r 'err_quit' .
# dump in c-style character
od -c file.hole
退出程序 ctrl + d
可变长参数列表
A function may be called with a varying number of arguments of
varying types. The include file
The called function must declare an object of type va_list which is used by the macros va_start(), va_arg(), and va_end().
The va_start() macro initializes ap for subsequent use by va_arg() and va_end()
The va_arg() macro expands to an expression that has the type and value of the next argument in the call
Each invocation of va_start() must be matched by a corresponding invocation of va_end() in the same function
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
void PrintFloats (int n, ...){
int i;
double val;
printf ("Printing floats:");
va_list vl; //build var arg list
va_start(vl,n); //beg of var arg list op
for (i=0; i < n; i++){
val = va_arg(vl,double); //expand arg by tyoe
printf (" [%.2f]",val);
}
va_end(vl); //end of var arg list op
printf ("\n");
}
...
PrintFloats(3,3.14159,2.71828,1.41421);
错误处理
程序运行中出现无法逆转、规避的错误时,需要打印错误信息并退出。
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
/*
* Fatal error unrelated to a system call.
* Print a message and terminate.
*/
void
err_quit(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
err_doit(0, 0, fmt, ap);
va_end(ap);
exit(1); //exit with err code
}
/*
* Print a message and return to caller.
* Caller specifies "errnoflag".
*/
static void
err_doit(int errnoflag, int error, const char *fmt, va_list ap)
{
char buf[MAXLINE];
//Write formatted data from variable argument list to sized buffer
vsnprintf(buf, MAXLINE-1, fmt, ap);
//printf sys error msg to buf
if (errnoflag)
snprintf(buf+strlen(buf), MAXLINE-strlen(buf)-1, ": %s",
strerror(error));
//add new line
strcat(buf, "\n");
fflush(stdout); /* in case stdout and stderr are the same */
fputs(buf, stderr);
fflush(NULL); /* flushes all stdio output streams */
}
调用时,
if (argc != 2)
err_quit("usage: ls directory_name");
ls的一种简单实现
#include <dirent.h> /*format of directory entries*/
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/*a pointer to be used to identify
the directory stream */
DIR *dp;
/* */
struct dirent *dirp; /*directory entry for traversal*/
if (argc != 2)
err_quit("usage: ls directory_name");
/*opens the directory named by filename */
if ((dp = opendir(argv[1])) == NULL)
err_sys("can't open %s", argv[1]);
/*returns a pointer to the next directory entry */
int cnt = 0;
while ((dirp = readdir(dp)) != NULL){
cnt++;
printf("[%d]%s\n", cnt, dirp->d_name);
}
/*closes the named directory stream and frees the
structure associated with the dirp pointer */
closedir(dp);
测试一下,列举当前目录下的所有文件。
KevinLiu$ ./ls1 ./
[1].
[2]..
[3]getcputc
[4]testerror.c
cat的一种简单实现
buffered实现
1
2
3
4
5
6
7
8
9
10
int n;
char buf[BUFFSIZE];
/*read from std input and write to std output */
while ((n = read(STDIN_FILENO, buf, BUFFSIZE)) > 0)
if (write(STDOUT_FILENO, buf, n) != n)
err_sys("write error");
if (n < 0)
err_sys("read error");
重定向,
# redirect stdout to tmp
$ ./mycat > tmp
test
# redirect stdin to tmp, print content of tmp
$ ./mycat < tmp
test
# redirect stdin and stdout, copy content of tmp to tmp_out
$ ./mycat < tmp > tmp_out
unbuffered实现
1
2
3
4
5
6
7
8
9
int c;
/* reads one character at a time */
while ((c = getc(stdin)) != EOF)
if (putc(c, stdout) == EOF) /* write one char at a time */
err_sys("output error");
if (ferror(stdin))
err_sys("input error");
自制简单的shell
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
char buf[MAXLINE]; /* from apue.h */
pid_t pid;
int status;
printf("%% "); /* print prompt (printf requires %% to print %) */
while (fgets(buf, MAXLINE, stdin) != NULL) { /* read one line at a time */
/* each line returned from fgets is terminated with \n */
if (buf[strlen(buf) - 1] == '\n')
buf[strlen(buf) - 1] = 0; /* replace newline with null */
if ((pid = fork()) < 0) { /*create new process */
err_sys("fork error");
} else if (pid == 0) { /* child */
/* exec cmd and replace the child process */
execlp(buf, buf, (char *)0); /* need null terminated argument*/
err_ret("couldn't execute: %s", buf);
exit(127);
}
/* parent wait the child process to exit*/
if ((pid = waitpid(pid, &status, 0)) < 0)
err_sys("waitpid error");
printf("%% ");
}
文件空洞
制造空洞文件,文件中的空洞不影响文件的大小。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
int fd;
if ((fd = creat("file.hole", FILE_MODE)) < 0)
err_sys("creat error");
if (write(fd, buf1, 10) != 10)
err_sys("buf1 write error");
/* offset now = 10 */
if (lseek(fd, 16384, SEEK_SET) == -1)
err_sys("lseek error");
/* offset now = 16384 */
if (write(fd, buf2, 10) != 10)
err_sys("buf2 write error");
/* offset now = 16394 */
设置文件状态标志
取文件状态标志,修改后设置回
1
2
3
4
5
6
7
8
9
10
11
12
13
14
void
set_fl(int fd, int flags) /* flags are file status flags to turn on */
{
int val;
if ((val = fcntl(fd, F_GETFL, 0)) < 0)
err_sys("fcntl F_GETFL error");
val |= flags; /* turn on flags */
// val &= ~flag; /* turn off flags */
if (fcntl(fd, F_SETFL, val) < 0)
err_sys("fcntl F_SETFL error");
}