UNIX环境高级编程C1(更)

记录学习UNIX高级环境编程的过程。

萌新路过,大神勿扰!!!

之前学习一直认为要深究到底,其实深究到底并没有什么错,但要掌握方法。

在一开始就出现了类似“upue.h”这个头文件,这个头文件其实是作者自己定义的,当然可以直接用,但是如果非要全部搞懂,这其实是没必要也是不现实的,在看过相关的教学视频,比如李慧琴的系统编程,大概就明白如何学习这本书。man手册其实是关键,通过man手册学习比直接看书能够学到更多的知识。

在三册书中,第三册其实要比第一册更好懂,第一册需要扎实的网络基础,必须和一本网络教程书共同学习,比如《计算机网络:自顶而下》。

首先就是贯穿全书的apue.h,可以自己创建这样一个头文件,并且通过不断地学习,将使用到的头文件,创建的函数不断地添加进去,从而得到自己的apue.h函数。

通过学习,在程序中尽量使用自己定义的函数是一种很好的习惯。

UNIX基础知识

第一部分:文件和目录

shell部分在《linux shell脚本编程》中已经说得很明白了,直接看1-3中的“列出一个目录中的所有文件”这个程序。

例子中使用的函数,分别为err_quit、err_sys、printf、opendir、closedir、readdir

opendir函数

opendir -- open a directory,打开一个目录

头文件:

#include <sys/types.h>
#include <dirent.h>

 DIR *opendir(const char *name);

返回值是一个叫DIR的指针,暂时不管是什么。

readdir函数

readdir -- read a directory

#include <dirent.h>

struct dirent *readdir(DIR *dirp);

closedir函数

closedir - close a directory

#include <sys/types.h>

#include <dirent.h>

int closedir(DIR *dirp);

err_quit函数

作用是命令行没有文件或者多于一个的时候,使用此函数进行输出,暂时考虑用一条printf实现。

err_sys函数

这个函数用于输出错误信息,类似于printf函数,和printf函数是相同的效果。

https://blog.csdn.net/qq_33706673/article/details/84729447中有关于printf如何实现的方法。

#include <stdio.h>
#include <dirent.h>

void err_sys(const char *str, ...)
{
    va_list var;
    char c = 0;
    unsigned int ui = 0;
    int i = 0;
    float f = 0;
    double d = 0;
    char *s = NULL;

    va_start(var, str);

    while ('\0' != *str)
    {
        if ('%' != *str)
        {
            printf("%c", *str);
            str++;
            continue;
        }

        else
        {
            switch (*(++str))
            {
            case 'c':
                c = (char)va_arg(var, int);
                printf("%c", c);
                break;

            case 'u':
                ui = (unsigned int)va_arg(var, int);
                printf("%u", ui);
                break;

            case 'd':
                i = va_arg(var, int);
                printf("%i", i);
                break;

            case 'f':
                f = (float)va_arg(var, double);
                printf("%f", f);
                break;

            case 'l':
                if ('f' == *(str + 1))
                {
                    d = va_arg(var, double);
                    printf("%lf", d);
                    str++;
                }
                break;

            case 's':
                s = (char *)va_arg(var, char *);
                printf("%s", s);
                break;

            default:
                printf("%c", *str);
                break;
            }
            str++;
        }
    }
    va_end(var);
}

UNIX环境高级编程C1(更)

UNIX环境高级编程C1(更)

 

apue.h文件(第一阶段)

/*头文件包含*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdarg.h>
#include <dirent.h>
#include <sys/types.h>

/*函数声明*/
void err_quit();                    /*文件打开失败*/
void err_sys(const char *str, ...); /*输出报错信息*/

/*函数原型*/
void err_quit()
{
    printf("Usage: ls directory_name");
}

void err_sys(const char *str, ...)
{
    va_list var;
    char c = 0;
    unsigned int ui = 0;
    int i = 0;
    float f = 0;
    double d = 0;
    char *s = NULL;

    va_start(var, str);

    while ('\0' != *str)
    {
        if ('%' != *str)
        {
            printf("%c", *str);
            str++;
            continue;
        }

        else
        {
            switch (*(++str))
            {
            case 'c':
                c = (char)va_arg(var, int);
                printf("%c", c);
                break;

            case 'u':
                ui = (unsigned int)va_arg(var, int);
                printf("%u", ui);
                break;

            case 'd':
                i = va_arg(var, int);
                printf("%i", i);
                break;

            case 'f':
                f = (float)va_arg(var, double);
                printf("%f", f);
                break;

            case 'l':
                if ('f' == *(str + 1))
                {
                    d = va_arg(var, double);
                    printf("%lf", d);
                    str++;
                }
                break;

            case 's':
                s = (char *)va_arg(var, char *);
                printf("%s", s);
                break;

            default:
                printf("%c", *str);
                break;
            }
            str++;
        }
    }
    va_end(var);
}

 

程序分析

1、程序功能是从命令行中读取一个文件目录然后再陈列其中的文件

if (argc != 2)
        err_sys("Usage: ls directory_name");

2、dirent.h头文件用于使用opendir和readdir函数

打开命令行中的第一个文件夹,鉴于opendir返回值是dp,且还要判断是否成功打开,否则报错。

打开:

DIR *dp;

opendir(argv[1])       /*打开*/

dp = opendir(argv[1])  /*返回值保存在一个DIR指针中*/

(dp = open[argv[1]] == NULL) /*判断是否打开*/

/*综上*/

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

读:opendir返回一个struct dirent

struct dirent *dirp;            /*保存readdir的返回值*/


readdir(dp);                    /*读刚才打开的文件*/
dirp = readdir(dp);            /*保存readdir的返回值*/
(dirp = readdir(dp)) != NULL;   /*判断dirp的值从而判断是否读*/


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

完整的list.c程序,用于列出目录中的名字:

#include "apue.h"

int main(int argc, char *argv[])
{
    DIR *dp;
    struct dirent *dirp;

    if (argc != 2)
        err_sys("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);
}

 

程序输出:

UNIX环境高级编程C1(更)


 

第二部分:输入和输出

文件描述符是一个小的非负整数,内核打开或创建一个新文件都会返回一个文件描述符。

读、写文件可以运用这个文件描述符。

运行一个程序的时候,shell会打开三个文件描述符,分别是标准输入、标准输出和标准错误。

标准I/O函数为那些不带缓冲的I/O提供了一个带缓冲的接口,使用标准I/O无需担心如何选取最佳的缓冲区大小。

 

函数

open,read,write,lseek、close提供了不带缓冲的I/O

标准输入和标准输出的文件描述符:STDIN_FILENO、STDOUT_FILENO

read函数,用man 2 read可查询相关信息:

read - read from a file descriptor

#include <unistd.h>

ssize_t read(int fd, void *buf, size_t count);

--- ssize_t  -> signed integer data types

write函数,用man 2 write查询
write - write to a file descriptor

#include <unistd.h>

ssize_t write(int fd, const void *buf, size_t count);
--- ssize_t  -> signed integer data types

fgetc,  fgets,  getc,  getchar,  ungetc - input of characters and strings

#include <stdio.h>

int getc(FILE *stream);

fputc,  fputs,  putc,  putchar,  puts  - output of characters and strings

#include <stdio.h>

int fputc(int c, FILE *stream);

clearerr, feof, ferror, fileno - check and reset stream status

#include <stdio.h>
int ferror(FILE *stream);

1.4

#include "apue.h"

#define BUFFSIZE 4096

int main(void)
{
    int n;
    char buf[BUFFSIZE];

    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");
    
    exit(EXIT_FAILURE);
}

 

1.5

#include "apue.h"

int main(void)
{
    int c;

    while ((c = getc(stdin)) != EOF)
        if ((putc(c, stdout)) == EOF)
            err_sys("output error");
    
    if(ferror(stdin))
        err_sys("input error");
    
    exit(EXIT_FAILURE);
}

 

第三部分:程序和进程

1、程序

程序是存储在磁盘上某个目录的可执行文件,内核使用exec函数(共7个),将程序读入内存并执行程序

2、进程和进程ID

程序的执行实例称为进程,UNIX的每一个进程有唯一的数字标识符,称为进程ID。

打印进程,使用getpid函数。

getpid, getppid - get process identification

#include <sys/types.h>
#include <unistd.h>

pid_t getpid(void);

#include "apue.h"

int main(void)
{

    printf("hello world from process ID %ld\n",(long)getpid);
    exit(EXIT_FAILURE);
}

UNIX环境高级编程C1(更)

3、进程控制

三个用于进程的函数:fork,exec,waitpod

 

 

 

 

 

时间值

UNIX系统用过两种不同的时间值。

1、日历时间

2、进程时间

--- 也称为CPU时间,用以度量进程使用的*处理器资源

--- 系统基本数据类型clock_t保存这种类型

UNIX系统为一个进程维护了3个进程时间值:时钟时间、用户CPU时间、系统CPU时间。

时钟时间又称为墙上时钟时间,它是度量进程运行的时间总量,其值与系统中同时运行的进程数有关。

用户CPU时间是指执行用户指令所用的时间量。系统CPU时间是为该进程执行内核程序所经历的时间。

要取得任一进程的时钟时间、用户时间和系统时间只要执行命令time(1),参数是度量其执行时间的命令。


 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 


 

 

上一篇:最小生成树Prim算法 Kruskal算法


下一篇:【01背包DP练习】洛谷 P1048采药 P1060开心的金明