您的位置:首页 > 产品设计 > UI/UE

Apue第一章

2017-05-21 23:04 148 查看
第一章主要介绍了关于linux体系的整体的结构,牵涉了许多计算机理论的知识,但是本书做的最好的地方是隐藏了许多计算机内部的细节,直接用简单的程序进行说明,言简意赅。

不过我们还是要简易说一下关于linux的体系。

首先linux是以根目录的形式进行目录的划分,这点和windows有很大的区别,linux的shell做的很完美,对于用户的交互功能做的很好。

关于linux的目录体系结构我们会在程序中演示

#include <unistd.h>
#include <stdio.h>
#include <dirent.h>
#include <string.h>
#include <sys/stat.h>
#include <stdlib.h>

int
main(int argc, char *argv[])
{
DIR *dp;
struct dirent *dirp;
if(argc != 2)
printf("cannot use\n");

if((dp = opendir(argv[1])) == NULL)
printf("open error\n");

while ((dirp = readdir(dp)) != NULL) {
printf("%s\t", dirp->d_name);
}

closedir(dp);
exit(0);
}

这个程序是用来打印目录下的所有文件的,很简单。

首先是一大堆头文件,有兴趣的朋友可以自己去查阅关于这些头文件的具体实现。

其次是DIR结构体和struct dirent结构体,这俩东西都是在dirent.h头文件中定义好的,我们只需要去关注我们程序中用到的细节。DIR类似于FILE,用于保存正在被读取的目录的有关信息,结构体我就我就不粘贴了。然后struct
dirent可以储存关于文件的信息。

在此程序中dp就类似于一个目录,那我们如何去索引这个目录下的所有文件呢?那就用dirp来储存吧。

其中还用到了两个函数opendir和readdir,建议你先man一下(不要问我man是什么)。

从名字你也能看出来这两个函数是干嘛用的,打开和读取呗。之后就是一个while的遍历输出,遍历目录下每一个索引号。有一个dirp->d_name参数,d_name就是struct
dirent结构体里面的一个变量,用于保存文件的名字。最后close目录退出程序。

以下是运行输出结果



接下来是一个标准输入输出的程序

#include <unistd.h>
#include <stdio.h>
#include <dirent.h>
#include <string.h>
#include <sys/stat.h>
#include <stdlib.h>

#define BUFFSIZE 4096

int
main(int argc, char *argv[])
{
int n;
char buf[BUFFSIZE];

while ((n = read(STDIN_FILENO, buf, BUFFSIZE)) > 0) {
if(write(STDOUT_FILENO, buf, n) != n)
perror("write error");
}

if(n < 0)
perror("read error\n");

exit(0);
}


这个程序就更简单了,read是一个不带有缓冲区的函数,需要你自己去定义buffer的值,我这里定义的是4096关于缓冲区我们后面的博客会讲到。然后read里面有一个STDIN_FILENO,write里面有一个STDOUT_FILENO,这样写是为了便于去增强程序的可读性,这个值是POSIX标准定义的,他们是0和1。这种数叫做幻数,有兴趣可以去查一查。我们先只需要记住只需要记住stdin的类型是FILE*,STDIN_FILENO的类型是int就可以了,用多了自然就明白了。我们后面还会学到read和write的用法,之后还会讲解。

以下是运行输出结果



这是也是一个标准输入输出程序

#include <unistd.h>
#include <stdio.h>
#include <dirent.h>
#include <string.h>
#include <sys/stat.h>
#include <stdlib.h>

int
main(int argc, char *argv[])
{
int c;
while((c = getc(stdin)) != EOF)
if(putc(c, stdout) == EOF)
perror("output error\n");

if(ferror(stdin))
perror("input error\n");
exit(0);
}

这个就是循环去标准输入中使用getc读取一个个字符,会产生阻塞,阻塞的概念我们后面会讲,然后这个程序就不再叙述,因为很简单啦,学过c的人应该都明白。



接下来是一个关于进程的程序

#include <unistd.h>
#include <stdio.h>
4000

#include <dirent.h>
#include <string.h>
#include <sys/stat.h>
#include <stdlib.h>
#include<sys/wait.h>

#define MAXLINE 4096

int
main(int argc, char *argv[])
{
char buf[MAXLINE];
pid_t pid;
int status;

printf("%%");
while (fgets(buf, MAXLINE, stdin)) {
if(buf[strlen(buf) - 1] == '\n')
buf[strlen(buf) - 1] =  0;

if((pid = fork()) < 0)
perror("fork error");
else if(pid == 0){
//printf("i am child\n");
execlp(buf, buf, (char *)0);
exit(127);
}

if(pid = waitpid(pid, &status, 0) < 0)
perror("waitpid error\n");
printf("%% ");
}
exit(0);
}

这个程序很有意思啦,功能大概是你自己写了一个shell,其实你是调用了linux的命令程序而已。关于进程的相关概念我们就用最简单的语言来描述吧,在windows下打开任务管理器是最直白的说明了,linux下使用命令ps
aux,现在我们只需要直到每个程序都有属于自己的进程就可以了。Fork函数就是把自己的资源复制了一份给儿子,返回值0表示子进程,返回值小于0表示fork错误。Execl函数和Waitpid函数请先man,在这里先不去讲解,后续会有说明。



下面这个程序只是多了一个信号处理的功能,当你按下ctrl+c的时候会向计算机发出一个SIGINT信号,程序有对应的sig_int函数去处理信号的到来。信号这个概念也只是抛砖引玉

#include <unistd.h>
#include <stdio.h>
#include <dirent.h>
#include <string.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <signal.h>
#include<sys/wait.h>

#define MAXLINE 4096

static void sig_int(int);

int
main(int argc, char *argv[])
{
char buf[MAXLINE];
pid_t pid;
int status;

if(signal(SIGINT, sig_int) == SIG_ERR)
perror("signal error\n");
printf("%%");
while (fgets(buf, MAXLINE, stdin)) {
if(buf[strlen(buf) - 1] == '\n')
buf[strlen(buf) - 1] =  0;

if((pid = fork()) < 0)
perror("fork error");
else if(pid == 0){
//printf("i am child\n");
execlp(buf, buf, (char *)0);
exit(127);
}

if(pid = waitpid(pid, &status, 0) < 0)
perror("waitpid error\n");
printf("%% ");
}
exit(0);
}

void
sig_int(int signo)
{
printf("interrupt\n%% ");
}





下面是error处理的一个简单程序

#include <unistd.h>
#include <stdio.h>
#include <dirent.h>
#include <string.h>
#include <sys/stat.h>
#include <stdlib.h>
#include<errno.h>

int
main(int argc, char *argv[])
{
fprintf(stderr, "EACCES: %s\n", strerror(EACCES));
errno = ENOENT;
perror(argv[0]);
exit(0);
}

错误的处理在linux编程中是非常重要的,处理各种不同的错误的提示信息对一个程序的健壮性是必不可少的,这个程序没什么说的看输出结果吧。



好了,第一章就这样吧,详细的还是大家自己去看书吧。

Ps:推荐一本书《linux程序设计》
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: