Entry

ちょっと前に読んだ本 - 『C言語撃退講座 ~K&Rは置いて、俺の話を聞け』

2008年08月09日

うーん……,まぁ一応読んだので紹介します。本書は入門本というよりは,C言語を知っている人の読み物といったところ。本書にしたがって C をはじめようと思うのは,ちょっと危険だと思います。

C言語撃退講座 ~K&Rは置いて、俺の話を聞け
丸岡 孝司
技術評論社
売り上げランキング: 59479

危険だってのは,例えば,次のようなコード(動くように加筆しています)。

#include <stdio.h>

int
main(int argc, char *argv[])
{
    int a;
    int b;

    a = 10;
    b = 20;
    
    printf("a = %d\n", a);
    printf("b = %d\n", b);

    a = a ^ b;
    b = a ^ b;
    a = a ^ b;

    printf("a = %d\n", a);
    printf("b = %d\n", b);
    
    return 0;
}

何やってるか分かるでしょうか。これを実行すると,こんな風になります。

aian@localhost ~
$ ./sample
a = 10
b = 20
a = 20
b = 10

要するに,a と b の値を入れ替えてるんですね。普通,変数の値を入れ替えるときは,一時変数を使ってするけれど,排他的論理和と使うと,一時変数を使わなくても変数の値を入れ替えることができるんです。

けど,こういう方法は,読みづらい上に汎用性がありません。例えば次のようなコード。

#include <stdio.h>

int
main(int argc, char *argv[])
{
    double a;
    double b;

    a = 10.0;
    b = 20.0;
    
    printf("a = %f\n", a);
    printf("b = %f\n", b);

    a = a ^ b;
    b = a ^ b;
    a = a ^ b;

    printf("a = %f\n", a);
    printf("b = %f\n", b);
    
    return 0;
}

これはコンパイルできません。実数型に論理演算は定義されていませんもんね。まぁ,次のように,無理矢理キャストすればコンパイルできなくもないんですが。

    a = (double)((int)a ^ (int)b);
    b = (double)((int)a ^ (int)b);
    a = (double)((int)a ^ (int)b);

これでも,int にキャストしたところで精度が失われてしまうので,コンパイルは通っても交換はできません。スワップできないので,こゆのをバグと言います。

ここでは,関数の中に直接書いたから,どこにバグがあるのか分かりやすかったんですけれど,上のキャストするコードをマクロなんかにしていたら,バグの原因をつかむのにかなり苦労するはずです。C++ のインライン関数と違って,C のマクロは型チェックをしないし,無理矢理キャストしているせいで,コンパイルエラーも出ないからです。こういうむやみにバグを仕込みそうなコードは,プロが書くコードじゃない(と思う)。

他にも,本書のコードは裏技的な要素が強いもんで,あまりおすすめできるもんがありません。配列の添字と配列名を入れ替えても動くんだよ!みたいなもんもある始末。こんなコードを書いている人が周りにいたら,はったおすところです。添字と配列名がアドレス計算の話としてどういう意味を持っているか知っているからしているんでしょうけれど,C の添字の意味をあえて無視したいんだったら,C じゃなくアセンブリで書くべきです。

初心者の役には立たないし,中級者は読むべきではないし(変な癖がつく),上級者にはつまらない,ってなことで,本書はなんとも微妙な本。ネタとして読むのもアリだけど,ネタに2000円を支払うか……これまた微妙なところです。

Trackback
Trackback URL:
Ads
About
Search This Site
Ads
Categories
Recent Entries
Log Archive
Syndicate This Site
Info.
クリエイティブ・コモンズ・ライセンス
Movable Type 3.36
Valid XHTML 1.1!
Valid CSS!
ブログタイムズ

© 2003-2012 AIAN