『ふつうのLinuxプログラミング』正誤表

$Id: errata.html,v 1.18 2005/10/29 21:11:55 aamine Exp $

まえがき

間違いではありませんが、サポートサイトの URL を載せるのを忘れました。 このページを御覧のかたには必要ないと思いますが、サポートサイトは http://i.loveruby.net/ja/linuxprog/ です。

第 3 章 Linuxを描き出す3つの概念

p.44

誤: RaiserFS
正: ReiserFS

第 5 章 ストリームにかかわるシステムコール

p.81

誤: また、付録Bにはこのようなデータ型のうち
正: また、付録A.2にはこのようなデータ型のうち

第 6 章 ストリームにかかわるライブラリ関数

p.106 表6.2

"a", "a+" について 「(ファイルが) 存在するならサイズを0にして新しく書き込みを開始する」 とありますが、いずれも 「(ファイルが) 存在するならそのファイルの末尾から書き込みを開始する」 が正です。

p.114 図6.5

図の左側、「Gooooooooogle\n」と最後に '\n' がついてしまっていますが、 この '\n' は不要です。

p.116

誤: fputs()は、ストリームからすべてのバイト列を読み終わったか、
     何か問題が起きたときはEOFを返します。

正: fputs()は、ストリームにすべてのバイト列を書き終わったか、
     何か問題が起きたときはEOFを返します。

p.129

「clearerror()」はすべて「clearerr()」の間違いです。

第 7 章 head コマンドを作る

p.142

誤: 最後に、if (!f)はif (f != NULL)と同じ意味です。
正: 最後に、if (!f)はif (f == NULL)と同じ意味です。

この if (!f) という書きかたについて質問がありました。 これはポインタ f が「あるか、ないか」をチェックする書法です。 つまり、非 NULL なら「ある」、NULL なら「ない」と考えるわけです。 C 言語の入門書ではこの書きかたをよくないと書いているものも多いのですが、 わたしはむしろこの書きかたのほうが本来的であると思います。 また、実際に多くのプログラムで使われていることを考えると、 少なくとも読めるようにはなっておくべきです。

なお、この書法を「NULL の値が 0 であることに頼った、不適切な手法」 だと言う人がいますが、それは間違いです。たとえば C 言語 FAQ の 5.3 項 を参照してください。

第 8 章

p.180 練習問題 1

「-f オプションと -v オプション」を実装しろと書いてありますが、 これは「-i オプションと -v オプション」の間違いです。 しかし問題を出してしまったものはしょうがないので、 サンプルコードでは -i, -f, -v の三つすべてを実装しておきました。

第 11 章 プロセスとハードウェア

p.249「スタティックリンク」の段落

誤: 中にはたくさんのオブジェクトファイルを収めています。
正: 中にはたくさんのオブジェクトファイルが収められています。

第 12 章 プロセスにかかわる API

p.272

誤: Linuxには、親子関係とはまったく関係なく
     プロセスを体系付ける別の概念もあります。

正: Linuxには、親子関係以外にもプロセスを体系付ける概念があります。

プロセスグループおよびセッションは 親から引き継がれますので、 「まったく関係ない」とは言えません。

第 13 章 シグナルにかかわる API

p.282

signal(2) のプロトタイプ宣言が間違っています。

誤: void (*signal(int sig, void (func*)(int)))(int);

正: void (*signal(int sig, void (*func)(int)))(int);

第 15 章 ネットワークプログラミングの基礎

p.328

パケットを再送するのは受け手ではなく送り手です。

誤: ある程度時間がたっても途中のデータが届かないようだと、
     受け手はもう一度パケットを送ってくれるように送り手に頼みます。

正: ある程度時間がたってもデータが届かないと、
     送り手はもう一度パケットを送り直します。

より正確に事情を描写するとこういうことです。 TCP/IP では、パケットを受け取ったら受け取り側が「受け取ったよ」 という確認パケット (ACK) を送り返すことになっています。 この ACK パケットがいつまでたっても返ってこない場合、 送り手はパケットが紛失されたとみなしてパケットを送り直します。

p.342

daytime クライアントの open_connection() において、 getaddrinfo の返り値のリンクリストを処理していますが、 ai にアクセスしなければいけないところで res にアクセスしています。 socket() と connect() の引数で使っている res はすべて ai です。 以下に diff を掲載します。

--- src/daytime.c       4 May 2005 09:24:03 -0000       1.7
+++ src/daytime.c       12 Oct 2005 19:18:06 -0000      1.8
@@ -46,11 +46,11 @@
         exit(1);
     }
     for (ai = res; ai; ai = ai->ai_next) {
-        sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
+        sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
         if (sock < 0) {
             continue;
         }
-        if (connect(sock, res->ai_addr, res->ai_addrlen) < 0) {
+        if (connect(sock, ai->ai_addr, ai->ai_addrlen) < 0) {
             close(sock);
             continue;
         }

また、修正後の open_connection() のコードは以下の通りです。

static int
open_connection(char *host, char *service)
{
    int sock;
    struct addrinfo hints, *res, *ai;
    int err;

    memset(&hints, 0, sizeof(struct addrinfo));
    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_STREAM;
    if ((err = getaddrinfo(host, service, &hints, &res)) != 0) {
        fprintf(stderr, "getaddrinfo(3): %s\n", gai_strerror(err));
        exit(1);
    }
    for (ai = res; ai; ai = ai->ai_next) {
        sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
        if (sock < 0) {
            continue;
        }
        if (connect(sock, ai->ai_addr, ai->ai_addrlen) < 0) {
            close(sock);
            continue;
        }
        /* success */
        freeaddrinfo(res);
        return sock;
    }
    fprintf(stderr, "socket(2)/connect(2) failed");
    freeaddrinfo(res);
    exit(1);
}

付録

A.1 (p.440)

オプションの列挙中にマイナスが抜けているところがあります。

誤: Dsymbol=value
正: -Dsymbol=value