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;これは、のちの言葉で言うと、 メンバーを指定することにより構造体のポインター型への、 暗黙の型変換(キャスト)がおこなわれているわけである。 当時、構造体のメンバー名は全構造体をつうじて一意だったので、 このような芸当が可能だったのである。
当時のドキュメントには型変換が見当たらない。 param.hには前項で見たように、 暗黙の型変換のための無名の構造体が定義されている。
/* * structure to access an * integer in bytes */ struct { char lobyte; char hibyte; }; /* * structure to access an integer */ struct { int integ; };
ところで、これを「代入演算子」と呼ぶのは変といえば変である。 「自己演算子(endo-operator)」とでも呼びたいところである。
特に、今日iを整数値に適当に使用するように、 pを汎用のポインターとして使っているあたりである。 一般のポインターから構造体メンバーへの参照が自由におこなえるのでこういう芸当が可能であった。