C言語

Version 6のUNIXのソースコードは「pre K&R」とよばれる古いCで記述されている。 現在のCの知識でだいたいはわかるが、理解に苦しむ個所もある。 うるさいことを言えば当時のリファレンスマニュアルを参照して、 当時の文法に親しむのが正攻法であろう。 が、とりあえず「これだけわかっていればソースは読める」というところだけ、 てっとりばやくまとめておこう。

構造体のポインター

なかでも衝撃的なのは、 構造体のポインターからメンバーを参照する演算子「->」が自由に使えることである。 たとえば、slp.cから関数setpri()を見てみると
setpri(up)
{
        register *pp, p;

        pp = up;
        p = (pp->p_cpu & 0377)/16;
        p =+ PUSER + pp->p_nice;
        if(p > 127)
                p = 127;
        if(p > curpri)
                runrun++;
        pp->p_pri = p;
}
のように、整数へのポインターであるppから構造体のメンバーに平気で参照を行っている。 メンバー名の頭に「p_」がついているのはproc.hで定義しているstruct procである。

Version 6のC Reference Manualの記述は以下のとおり。

7.1.8 primary-expression -> member-of-structure

The primary-expression is assumed to be a pointer which points to an object of the same form as the structure of which the member-of-structure is a part. The result is an lvalue appropriately offset from the origin of the pointed-to structure whose type is that of the named structure member. The type of the primary-exporession need not in fact be pointer, it is sufficient that it be a pointer, character, or integer.
すなわち、左辺は構造体へのポインターでなくてもよいのはもちろん、ポインターである必要すらない。 整数型はともかく文字型でもよいのである。

たとえば、関数main()の冒頭部にある

        UISD->r[0] = 077406;
がそうである。これはいずれもseg.hで定義されていて
#define   UISD    0177600         /* first user I-space descriptor register */
および
/*
 * structure used to address
 * a sequence of integers.
 */
struct
{
        int     r[];
};
となっている(Lions本では後者はparam.hに移っている)。つまり、整数値から 直接構造体のメンバー(しかも要素数の指定のない配列)にアクセスしているの である。
        0177600->r[0] = 077406;
これは、のちの言葉で言うと、 メンバーを指定することにより構造体のポインター型への、 暗黙の型変換(キャスト)がおこなわれているわけである。 当時、構造体のメンバー名は全構造体をつうじて一意だったので、 このような芸当が可能だったのである。

上記とも絡んでくるが、当時は現在のCよりも型のしばりがゆるかった。 関数のプロトタイプ宣言もなかった。

当時のドキュメントには型変換が見当たらない。 param.hには前項で見たように、 暗黙の型変換のための無名の構造体が定義されている。

/*
 * structure to access an
 * integer in bytes
 */
struct
{
        char    lobyte;
        char    hibyte;
};

/*
 * structure to access an integer
 */
struct
{
        int     integ;
};

代入演算子

現在は「x -= 1」などと書かれている代入演算子が、 当時は「x =- 1」と書かれていた。 これは「x = -1」とまぎらわしく、あきらかな欠陥である。 これについてはDennis Ritchieが多少の説明を書いている。

ところで、これを「代入演算子」と呼ぶのは変といえば変である。 「自己演算子(endo-operator)」とでも呼びたいところである。

変数

文法上の違いではないが、UNIX第6版のソースコードを見ていてくらくらするのは、 変数を自由に多義的に使用していることである。 すなわち、関数のなかで変数の意味がころころ変わる。 このへんの感覚はアセンブラ的とすら言えるかもしれない。

特に、今日iを整数値に適当に使用するように、 pを汎用のポインターとして使っているあたりである。 一般のポインターから構造体メンバーへの参照が自由におこなえるのでこういう芸当が可能であった。

プリプロセッサ

defineとincludeが使われている。 Cコンパイラには、ファイルの先頭が「#」で始まるファイルのみ前処理する、 というルールがある。
戻る