学习笔记——《unix环境高级编程(第三版)》第一章实例

时间:2022-06-22 20:36:33

1-3 列出一个目录中的所有文件

#include "apue.h"
#include "dirent.h"

int main(int argc,char *argv[])
{
    DIR             *dp;     //定义了一个DIR 结构体变量
    struct dirent   *dirp;   //定义了一个dirent 结构体变量


    if(argc !=2)                   
        err_quit("usage: ls directory_name");          

    if(dp=opendir(argv[1])==NULL)
        err_sys("can't open %s",argv[1]);

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

    closedir(dp);
    exit(0);


}

DIR结构体的定义:

struct __dirstream   
   {   
    void *__fd;    
    char *__data;    
    int __entry_data;    
    char *__ptr;    
    int __entry_ptr;    
    size_t __allocation;    
    size_t __size;    
    __libc_lock_define (, __lock)    
   };   

typedef struct __dirstream DIR;  

dirent结构体的定义:

struct dirent   
{   
  long d_ino; /* inode number 索引节点号 */  
     
    off_t d_off; /* offset to this dirent 在目录文件中的偏移 */  
     
    unsigned short d_reclen; /* length of this d_name 文件名长 */  
     
    unsigned char d_type; /* the type of d_name 文件类型 */  
     
    char d_name [NAME_MAX+1]; /* file name (null-terminated) 文件名,最长255字符 */  
}  

参考了Linux下DIR,dirent,stat等结构体详解


1-4 将标准输入复制到标准输

#include "apue.h"
#define BUFFSIZE 4096

int main(void)
{
    int         n;
    char    buf[BUFFSIZE];      
while (n=read(STDIN_FILENO,buf, BUFFSIZE) > 0 )     //read函数:读取STDIN_FILENO(标准输入)的数据储存到字符串buf中,大小为BUFFSIZE,并返回读取的字符大小
    if(write(STDOUT_FILENO,buf,n) !=n)              //write函数类似于read函数
        err_sys("write error");


if(n<0)
    err_sys("read error");


exit(0);
}

文件描述符:内核(kernel)利用文件描述符(file descriptor)来访问文件。文件描述符是非负整数。打开现存文件或新建文件时,内核会返回一个文件描述符。读写文件也需要使用文件描述符来指定待读写的文件。

注意:read、write提供的是不带缓冲的I/O,使用的是文件描述符

类似的还有:open、lseek、close


1-5 使用标准I/O讲标准输入复制到标准输出

#include "apue.h"

int main()
{
int         c;

while((c = getc(stdin)) != EOF)      //getc函数:从文件指针stdin指向的文件流中读取一个字符,并把它作为函数值返回给整型变量c,并把位置标识符往前移动,读入字符不成功则返回值为EOF。
    if(putc(c,stdout) == EOF)        //putc函数:在stdout所指向的文件的当前读写位置写入一个字符。写入字符成功则函数返回值为该字符的ASCII值,写入字符不成功则返回值为EOF。
        err_sys("output error");

if(ferror(stdin))
    err_sys("input error");

exit(0);

}

注:和不带缓冲的I/O函数比较起来,带缓冲的I/O不用定义BUFFSIZE大小,并不用在输入函数中接入参数表示大小


1-6 打印进程ID

#include "apue.h"

int main(void)
{
   printf("Hello world from process ID %ld\n",(long)getpid);    //getpid函数:功能是取得进程识别码,许多程序利用取到的此值来建立临时文件,以避免临时文件相同带来的问题。
   exit(0);
}


1-7 从标准输入读命令并执行

#include "apue.h"
#include "sys/wait.h"

int main(void)
{   
    char buf[MAXLINE];      //定义于apue.h
    pid_t pid;
    int status;

    printf("%% ");         //打印出% 
    while(fgets(buf, MAXLINE, stdin) !=NULL)
        {
            if(buf[strlen(buf)-1]=='\n')
                buf[strlen(buf)-1]=0;        //由于execlp函数需要的字符串以NULL(0)结尾,把'\n'换成0
            if(pid = fork() < 0)
                err_sys("fork error");
            else if(pid==0)
                {
                    execlp(buf, buf, (char *)0);
                    err_ret("couldn't execute: %s",buf);
                    exit(127);
                }

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

execlp函数的百度百科解释:

execlp()会从PATH 环境变量所指的目录中查找符合参数file的文件名,找到后便执行该文件,然后将第二个以后的参数当做该文件的argv[0]、argv[1]……,最后一个参数必须用空指针(NULL)作结束。如果用常数0来表示一个空指针,则必须将它强制转换为一个字符指针,否则它将解释为整形参数,如果一个整形数的长度与char * 的长度不同,那么exec函数的实际参数就将出错。如果函数调用成功,进程自己的执行代码就会变成加载程序的代码,execlp()后边的代码也就不会执行了.


1-8 示例strerror 和 perror

#include "apue.h"
#include "errno.h"

int main(int argc, char *argv[])
{
    fprintf(stderr,"EACCES: %s\r", strerror(EACCES));    //stderr是标准错误,不会把数据放到缓冲区,而是直接输出!
    errno = ENOENT;                        //ENOENT一般是没找到文件或路径,包括因为权限问题没找到的情况。
    perror(argv[0]);
    exit(0);
}

疑惑:

不清楚EACCES是什么东西

1-9打印出用户ID和组ID

#include "apue.h"

int main(void)
{
    printf("uid = %d, gid = %d\n",getuid(),getgid());
    exit(0);

}

1-10 在1-7的基础上,捕获退出的信号

#include "apue.h"
#include "sys/wait.h"

static void sig_int(int);  //信号捕获函数


int main(void)
{   
    char buf[MAXLINE];      //定义于apue.h
    pid_t pid;
    int status;

    if(signal(SIGINT, sig_int) == SIG_ERR)
        err_sys("signal error");


    printf("%% ");         //打印出% 
    while(fgets(buf, MAXLINE, stdin) !=NULL)
        {
            if(buf[strlen(buf)-1]=='\n')
                buf[strlen(buf)-1]=0;        //由于execlp函数需要的字符串以NULL(0)结尾,把'\n'换成0
            if(pid = fork() < 0)
                err_sys("fork error");
            else if(pid==0)
                {
                    execlp(buf, buf, (char *)0);
                    err_ret("couldn't execute: %s",buf);
                    exit(127);
                }

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

void sig_int(int signo)
{   

    printf("interrupt\n%% ");

}