XDR ライブラリは識別型の共用体もサポートしています。識別型の共用体は、C の共用体に、共用体の「アーム」を選択する enum_t
型の値が付加されたものです。
struct xdr_discrim { enum_t value; bool_t (*proc)(); }; bool_t xdr_union(xdrs, dscmp, unp, arms, defaultarm) XDR *xdrs; enum_t *dscmp; char *unp; struct xdr_discrim *arms; bool_t (*defaultarm)(); /* may equal NULL */
このルーチンでは、最初に *dscmp にある要素識別子を変換します。要素識別子は常に enum_t
型です。次に、*unp にある共用体が変換されます。引数 arms は xdr_discrim 構造体配列へのポインタです。各構造体には、[value,proc] のペアが入っています。共用体の要素識別子が対応する valueと一致すれば、それに対する proc() が呼び出されて共用体が変換されます。xdr_discrim 構造体配列の終わりは、ルーチンの値が NULL(0) なので判別できます。arms 配列の中に要素識別子に一致するものがない場合は、defaultarm() 手続きが NULL でなければそれが呼び出されます。NULL の場合は FALSE を返します。
共用体のデータ型は、整数、文字へのポインタ (文字列)、gnumbers 構造体のどれかとします。また、共用体と現在の型は構造体で宣言されているとします。宣言は次のようになります。
enum utype {INTEGER=1, STRING=2, GNUMBERS=3}; struct u_tag { enum utype utype; /* 共用体の要素識別子 */ union { int ival; char *pval; struct gnumbers gn; } uval; };
例 A-12 では、合成データと XDR 手続きで、識別型共用体のシリアライズ (またはデシリアライズ) を行います。
struct xdr_discrim u_tag_arms[4] = { {INTEGER, xdr_int}, {GNUMBERS, xdr_gnumbers} {STRING, xdr_wrapstring}, {__dontcare__, NULL} /* アームの最後は常に NULL の xdr_proc */ } bool_t xdr_u_tag(xdrs, utp) XDR *xdrs; struct u_tag *utp; { return(xdr_union(xdrs, &utp->utype, &utp->uval, u_tag_arms, NULL)); }
xdr_gnumbers() については「XDR ライブラリ」の節で説明し、xdr_wrapstring() はサンプルプログラム C に示しました。この例では、xdr_union()のデフォルトの arm 引数 (最後の引数) には NULLを渡しています。したがって、共用体の要素識別子の値は、u_tag_arms 配列にリストした値のどれかでなければなりません。また、この例から、arm 配列の要素はソートされていなくてもよいことがわかります。
要素識別子は、この例では連続した値を取っていますが、連続しなくてもよいことを指摘しておく必要があります。要素識別子の型の各要素に、明示的に整数値を割り当てておくのはよい習慣です。こうすると、要素識別子の外部表現のドキュメントにもなりますし、異なる C コンパイラでも要素識別子が同じ値で出力されることが保証されます。