nekoTheShadow’s diary

技術ブログとして始めたはずが、読書&愚痴ブログになりました(´・ω・`)

青木峰郎『ふつうのLinuxプログラミング[第2版]: Linuxの仕組みから学べるgccプログラミングの王道』(SBクリエイティブ)

本書がメインテーマとしているのは「Linuxに用意されている、システムとのやり取りをするためのAPI」。すなわちシステムコールの概念や方法をC言語プログラミングを通じて学ぶことができる1冊です。たとえばlsmvpwdなど、普段何気なく利用しているコマンドがKernelとどのようなやり取りをしているのか? 基礎的だが、おざなりにされがちな部分を学ぶことができて、Linuxに対する理解が深まりました。個人的には

このあたりの「わかったふりをしてきた」ところをきっちり学びなおすことができてよかったと思います。プログラマである以上は仕組みが分かったうえで、便利なものを使うという態度を徹底したいものです。しったかぶりを決め込む、わからないものをわからないままにしておくのはだめ絶対(´・ω・`)

筆者の狙いかどうかはわかりませんが「プログラミングを通じて学ぶ」というのが本書の良書たるゆえんだと思いました。Linuxに書かれた本は数多くあれど、そのほとんどは知識として学ぶだけで、読んだ後にきちんと知識が定着しているかどうかというと、実はちょっとあやしい。一方、本書は大量のソースコードが掲載されており、読者は自由に写経することが可能です(実際わたしも全コードをすべて写経しました)。写経とはいえ、実際に手を動かすのと動かさないのでは、知識の身に付き具合が全く違います。忙しいとついついおっくうになりがちですが、これからも意識的に手を動かしていきたいところです。

最後に読者プレゼント(?)。まずは本書を読み終わった後に、なんとなく作成したなんちゃってlsコマンド。本書の途中でlsコマンドを作成するくだりがあるのですが、それとほぼいっしょのような……。

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

int
main(int argc, char *argv[]) {
    if (argc == 1) {
        fprintf(stderr, "NO ARGS\n");
        exit(1);
    }

    for (int i = 1; i < argc; i++) {
        char *dirname = argv[i];
        DIR *dir = opendir(dirname);
        if (!dir) {
            perror(dirname);
            exit(1);
        }

        struct dirent *ent;
        while (ent = readdir(dir)) {
            char *filename = ent->d_name;
            if (strcmp(filename, ".") == 0 || strcmp(filename, "..") == 0) continue;
            printf("%s\n", filename);
        }
        
        if (closedir(dir) < 0) {
            perror(dirname);
            exit(1);
        }
    }
}

もうひとつが標準入力やファイルから1行すべてを読み込むreadline関数を作ったので、こちらもなんとなく公開しておきます。本書はその性質上、ファイルから1行読み込む処理を何度も書く必要があるのですが、そのたびにfgetsを使うのは面倒。とくにいちいち文字数を指定するのはおっくうなので、その必要のない関数を用意しておき、使いまわしていました(´・ω・`) 何かのお役に立てば幸いです(´・ω・`)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define LEN 100

char *readline(FILE *stream);
char *xalloc(char *ptr, int len);
void die(char *str);

char *readline(FILE *stream) {
    int len = LEN;
    char *line = xalloc(NULL, len);

    char ch;
    int i;
    for (i = 0; ;i++) {
        if (i == len) {
            len += LEN;
            line = xalloc(line, len);
        }

        ch = getc(stream);
        if (ch == EOF || ch == '\n') break;
        line[i] = ch;
    }

    if (i == 0 && ch == EOF) return NULL;
    line[i] = '\0';
    return line;
}

void die(char *str) {
    fprintf(stderr, "failed to %s\n", str);
    exit(1);
}

char *xalloc(char *ptr, int len) {
    int size = len * sizeof(char);
    void *str = realloc(ptr, size);

    if (str == NULL) {
        if (ptr != NULL) {
            free(ptr);
        }
        die("xalloc");
    }

    return str;
}