第八章 异常控制流
练习题 8.6:编写一个叫做myecho的程序,它打印出它的命令行参数和环境变量。
#include <unistd.h> #include <sys/types.h> #include <stdlib.h> #include <stdio.h> int main(int argc, char *argv[], char *envp[]) { printf("Command line arguments:\n"); for (int i = 0; i < argc; ++ i) printf(" argv[%d]: %s\n", i, argv[i]); printf("Enviroment variables:\n"); for (int i = 0; envp[i]; ++ i) printf(" envp[%d]: %s\n", i, envp[i]); return 0; }
练习题 8.7:编写名为snooze的程序,有一个命令行参数,使用该参数调用练习题8.5中的snooze函数,然后终止。编写程序,使得用户可以通过在键盘上输入 crtl-c
中断snooze函数。
// snooze.c #include <sys/types.h> #include <unistd.h> #include <stdio.h> #include <signal.h> #include <stdlib.h> #include <errno.h> #include <string.h> extern int errno; unsigned int snooze(unsigned int secs); void handler(int sig); int main(int argc, char *argv[]) { unsigned int rest_seconds = 0; unsigned int secs = argv[1][0] - '0'; if (signal(SIGINT, handler) == SIG_ERR) { fprintf(stderr, "signal error: %s\n", strerror(errno)); exit(0); } rest_seconds = snooze(secs); printf("User hits crtl-c after %u seconds\n", secs - rest_seconds); return 0; } unsigned int snooze(unsigned int secs) { int rest_seconds = sleep(secs); printf("Sleep for %u of %u seconds\n", secs - rest_seconds, secs); return rest_seconds; } void handler() {}
练习题8.20:使用execve编写一个名为myls的程序,该程序的行为和 /bin/ls 程序一样。
// myls.c #include <unistd.h> #include <sys/types.h> #include <stdlib.h> extern char **environ; int main(int argc, char *argv[]) { execve("/bin/ls", argv, environ); exit(0); }
练习题 8.22
// mysystem.c #include <unistd.h> #include <sys/types.h> #include <stdlib.h> #include <stdio.h> #include <errno.h> extern int erron; extern char **environ; extern int EINTP; int mysystem(char *command) { pid_t pid; int status; if (command == NULL) return -1; if ((pid = fork()) == -1) return -1; if (pid == 0) { char *argv[4]; argv[0] == "sh"; argv[1] == "-c"; argv[2] == command; argv[3] == NULL; execve("bin/sh", argv, environ); exit(-1); // control should never come here } while (1) { if (waitpid(pid, &status, 0) == -1) { if (errno != EINTR) exit(-1); } else { if (WIFEXITED(status)) return WEXITSTATUS(status); else return status; } } }
习题8.24
// 8.24.h #include <stdio.h> #include <unistd.h> #include <string.h> #include <sys/types.h> #include <sys/wait.h> #include <error.h> #include <signal.h> extern int errno; extern int ECHILD; extern void psignal(int signal, const char *str); #define NCHILDREN 2 #define MAXLINE 80 char buf[MAXLINE]; int main() { int status; pid_t pid; for (int i = 0; i < NCHILDREN; ++ i) { pid = fork(); if (pid == 0) *(char *)main = 1; } while (pid = wait(&status) > 0) { if (WIFEXITED(status)) printf("child %d terminated normally with exit status = %d\n", pid, WEXITSTATUS(status)); else if (WIFSIGNALED(status)) { sprintf(buf, "child %d terminated by signal %d: ", pid, WTERMSIG(status)); psignal(WTERMSIG(status), buf); } } if (errno != ECHILD) { fprintf(stderr, "%s: %s\n", "wait error", strerror(errno)); exit(0); } return 0; }
习题8.25 编写fgets函数的一个版本tfgets,他5秒中后就会超时。tfgets 函数接收和 fgets 相同的参数。如果用户在5秒内不键入一个输入行,tfgets返回NULL。
否则,返回一个指向输入行的指针。
// tfgets.c #include <unistd.h> #include <sys/types.h> #include <signal.h> #include <string.h> #include <setjmp.h> #include <stdio.h> #include <stdlib.h> static sigjmp_buf env; void handler(int signal) { alarm(0); longjmp(env, 1); } char *tfgets(char *buffer, int buffer_size, FILE *stream) { signal(SIGALRM, handler); alarm(5); if (!sigsetjmp(env, 1)) return fgets(buffer, buffer_size, stream); else return NULL; } int main() { char *str; char buffer[100]; while (1) { if (tfgets(buffer, sizeof(buffer),stdin) != NULL) printf("read: %s", buffer); else printf("time out\n"); } exit(0); }