この付録では、XDR プロトコル言語の仕様について説明します。
外部データ表現 (external data representation: XDR) は、データの記述と符号化の標準規約です。XDR プロトコルは、異なるコンピュータアーキテクチャ間のデータ伝送に利用できます。これまで、種々のマシン間のデータ通信に使用されてきました。XDR は、ISO の参照モデルのプレゼンテーション層 (第 6 層) に対応するもので、X.409 「ISO 抽象構文表記」におおむね従っています。XDR と X.409 との一番大きな違いは、XDR が暗黙的データ型を使用するのに対して、X.409 は明示的データ型を使用する点です。
XDR では、言語を使用してデータ形式を記述しますが、この言語はプログラミング言語ではないので、データの記述のためにだけしか使用できません。XDR 言語を使用すると、複雑なデータ形式も簡潔に表現できます。XDR 言語は C 言語に似ています。RPC や NFS のようなプロトコルでは、XDR でデータ形式を記述しています。
XDR 標準規約では、バイト (オクテット) は移植可能な 8 ビットデータとみなしています。
この章では、データの説明や比較のときに、グラフィックボックス表現を使用します。ほとんどの場合、各ボックスが 1 バイトを表します。各バイトは 0 〜 n-1 で番号付けされます。データは、バイト m がバイト m+1 の直前に位置するという関係が保たれるバイトストリームで読み書きされます。データ項目はすべて 4 バイト (32 ビット) の倍数で表現されます。n バイトのデータの後には、0 〜 3 個の余分なゼロバイト r が付加されて、全体のバイト数が 4 の倍数になるように調整されます。ボックス間にある省略記号は、1 バイト以上の追加が必要が、またはまったく必要でないことを表します。次にその例を示します。

XDR のブロックサイズの選択はさまざまな条件の兼ね合いで決まります。2 のような小さな値を選択して符号化データを小さくすると、そのようなデータ境界を使用しないマシンでは整合の問題が起こります。8 のような大きな値にすると、事実上すべてのマシンでデータ整合が可能になりますが、符号化データが大きくなり過ぎます。妥協案として 4 が選ばれました。4 は適度な大きさでほとんどのアーキテクチャに対応できます。
ただし Cray コンピュータで標準 XDR が使用できないわけではありません。各データ項目のオーバヘッドが、4 バイト (32 ビット) アーキテクチャのマシンより大きくなるという意味です。4 という値は符号化データを妥当なサイズに押さえる意味でも適当な値です。
どのマシンでも同じデータは同じ値に符号化されなければ、符号化データを比較したりチェックサムを取ったりできません。したがって、可変長データの最後は、ゼロデータでパディングしなければなりません。
XDR 標準規約で定義されているデータ型を説明します。
XDR 言語でどのようにデータ型を宣言するかを示します。
符号化方法を図示します。
XDR 言語で使用できる各データ型の宣言方法を示します。大小記号による括弧 (< と >) は可変長のデータシーケンスを示し、角括弧 [ と ])は固定長のデータシーケンスを示します。n、m、r は整数を表します。XDR 言語の詳細仕様については、「XDR 言語仕様」の節を参照してください。
いくつかのデータ型については、具体的なデータ記述例も示します。より詳しいデータ記述例については、「XDR データ記述 」を参照してください。
XDR の符号付き整数は、[-2147483648, 2147483647] の範囲の整数が符号化された 32 ビットデータです。整数は 2 の補数で表されます。最上位バイト (MSB) と最下位バイト (LSB) はそれぞれバイト 0 とバイト 3 です。
整数は次のように宣言します。
int identifier;
整数

XDR の符号なし整数は、[0, 4294967295] の範囲の正の整数が符号化された 32 ビットデータです。整数は符号なしの 2 進数で表されます。最上位バイト (MSB) と最下位バイト (LSB) はそれぞれバイト 0 とバイト 3 です。
符号なし整数は次のように宣言します。
unsigned int identifier;
符号なし整数

列挙型のデータ表現方法は符号付き整数と同じです。列挙型は、整数のサブセットを記述するのに便利です。
列挙型は次のように宣言します。
enum {name-identifier = constant , ... } identifier;
たとえば、列挙型を使用して赤、黄、青の 3 色を次のように表すことができます。
enum {RED = 2, YELLOW = 3, BLUE = 5} colors;
列挙型に、enum 宣言で指定されていない整数を代入しようとするとエラーになります。
「符号付き整数」を参照してください。
ブール型は、標準規約の明示型に対応するための型で、よく使用される重要なデータ型です。ブール型には、整数の 0 と 1 を使用します。
ブール型は次のように宣言します。
bool identifier;
これは、次の宣言と同じです。
enum {FALSE = 0, TRUE = 1} identifier;
「符号付き整数」を参照してください。
標準規約では 64 ビット (8 バイト) の整数として hyper int と unsigned hyper int を定義しています。その表現方法は明らかに、上で説明した integer と unsigned integer を拡張したものです。hyper 整数は 2 の補数で表されます。最上位バイト (MSB) と最下位バイト (LSB) はそれぞれバイト 0 とバイト 7 です。
Hyper 整数は次のように宣言します。
hyper int identifier; unsigned hyper int identifier;
Hyper 整数

標準規約では、浮動小数点型 float (32 ビット、すなわち 4 バイト) を定義しています。符号化方法は、正規化された単精度浮動小数点に関するIEEE 標準規約 [1] に従います。単精度浮動小数点は次の 3 つのフィールドで記述されます。
S: 符号を表す 1 ビットのフィールドです。0 が正、1 が負を表します。
E: 数値の指数部 (基数は 2) を表します。このフィールドは 8 ビットです。指数部の値を 127 だけバイアスした値が入っています。
F: 数値の仮数部 (基数は 2) を表します。このフィールドは 23 ビットです。
したがって、単精度浮動小数点型の値は次のように記述されます。
(-1)**S * 2**(E-Bias) * 1.F
単精度浮動小数点データは次のように宣言します。
float identifier;
倍精度浮動小数点データは次にように宣言します。
double identifier;
倍精度浮動小数点

整数の最上位バイトと最下位バイトがバイト 0 とバイト 3 であるのと同様に、倍精度浮動小数点型の値の最上位ビットと最下位ビットはビット 0 とビット 63 になります。S、E、F の各フィールドの開始ビット (最上位ビット) のオフセットはそれぞれ 0、1、12 になります。
これらのオフセットは論理的ビット位置を示すもので、物理的位置を示すものではありません (物理的位置は媒体によって異なります)。
符号付きゼロ、符号付き無限大 (オーバフロー)、正規化されない値 (アンダフロー) の符号化については、IEEE 標準規約 [1] を参照してください。IEEE 標準規約によると、NaN (not a number) は、システムごとに異なるため外部表現では使用できません。
標準規約では、4 倍精度浮動小数点型 quadruple (128 ビット、すなわち 16 バイト) を定義しています。符号化方法は、正規化された 4 倍精度浮動小数点に関する IEEE 標準規約 [1] に従います。標準規約では、4 倍精度浮動小数点は次の 3 つのフィールドに符号化されます。
S: 符号を表す 1 ビットのフィールドです。0 が正、1 が負を表します。
E: 数値の指数部 (基数は 2) を表します。このフィールドは 15 ビットです。指数部の値を 16383 だけバイアスした値が入っています。
F: 数値の仮数部 (基数は 2) を表します。このフィールドは 111 ビットです。
したがって、4 倍精度浮動小数点型の値は次のように記述されます。
(-1)**S * 2**(E-Bias) * 1.F
quadruple identifier;
4 倍精度浮動小数点

整数の最上位バイトと最下位バイトがバイト 0 とバイト 3 であるのと同様に、4 倍精度浮動小数点型の値の最上位ビットと最下位ビットはビット0 とビット 127 になります。S、E、F の各フィールドの開始ビット (最上位ビット) のオフセットはそれぞれ 0、1、16 になります。これらのオフセットは論理的ビット位置を示すもので、物理的位置を示すものではありません。物理的位置は媒体によって異なります。
符号付きゼロ、符号付き無限大 (オーバフロー)、正規化されない値 (アンダフロー) の符号化については、IEEE 標準規約 [1] を参照してください。IEEE 標準規約によると、NaN (not a number) は、システムごとに異なるため外部表現では使用できません。
内容を解釈しない固定長データをマシン間で受け渡さなければならない場合があります。このデータを隠されたデータといいます。
隠されたデータは次のように宣言します。
opaque identifier[n];
ここで定数 n は、隠されたデータを入れるのに必要な (固定) バイト数です。n バイトの隠されたデータの後には、0 〜 3 個の余分なゼロバイト r が付加されて、隠されたオブジェクト全体のバイト数が 4 の倍数になるように調整されます。
n バイトの隠されたデータの後には、0 〜 3 個の余分なゼロバイト r が付加されて、隠されたオブジェクト全体のバイト数が 4 の倍数になるように調整されます。
固定長の隠されたデータ

標準規約では、可変長 (カウント付き) の隠されたデータも次のように定義されています。n バイトの任意のバイトシーケンス(バイト番号は 0 〜 n-1) がカウントされて下に示すように符号なし整数 n に符号化され、その後に n バイトのバイトシーケンスが続きます。
シーケンス内のバイト b は必ずバイト b+1 の直前に位置し、シーケンス内のバイト 0 はバイトシーケンスの長さ (カウント) の次に位置しています。n バイトのデータの後には、0〜 3 個の余分なゼロバイト r が付加されて、全体のバイト数が 4 の倍数になるように調整されます。
可変長の隠されたデータは次のように宣言します。
opaque identifier<m>;
または
opaque identifier<>;;
定数 m は、シーケンスに含まれるバイト数の上限を示します。2 番目の宣言のように m を指定しないと、最大バイト数は (2**32) - 1 となります。たとえば、ファイル伝送プロトコルで最大データ伝送サイズを 8192 バイトとするには、次のように宣言します。
opaque filedata<8192>;
可変長の隠されたデータ

指定した最大バイト数以上の長さを符号化するとエラーになります。
標準規約では、n バイトの ASCII 文字列 (バイト番号は 0〜 n-1) を次のように定義します。バイト数が符号なし整数 n に符号化されたものに、n バイトの文字列が続きます。文字列のバイト b は必ずバイト b+1 の直前に位置し、文字列のバイト 0 は文字列の長さの次に位置しています。n バイトのデータの後には、0 〜 3 個の余分なゼロバイト r が付加されて、全体のバイト数が 4 の倍数になるように調整されます。
カウント付きバイト文字列は次のように宣言します。
string object<m>;
または
string object<>;
定数 m は、文字列に含まれるバイト数の上限を示します。2 番目の宣言のように、m を指定しないと、最大バイト数は (2**32) - 1 となります。定数 m は、通常プロトコル仕様で決められています。たとえば、ファイル伝送プロトコルでファイル名を最大 255 バイトとするには、次のように宣言します。
string filename<255>;
文字列

指定した最大バイト数以上の長さを符号化するとエラーになります。
固定長配列の要素番号は 0 〜 n-1 で、個々の配列要素が 0 〜 n-1 の番号順に符号化されます。各配列要素のバイト数は 4 の倍数になっています。全要素が同一のデータ型であっても、要素のサイズが異なることがあります。たとえば、文字列の固定長配列の場合、要素のデータ型はすべて string 型ですが、個々の要素の長さは異なります。
各要素のデータ型がすべて同じである固定長配列は、次のように宣言します。
type-name identifier[n];
固定長配列

可変長配列をカウント付きで符号化することによって、固定長の要素と同じように符号化できます。要素カウント n (符号なし整数) に続けて、要素番号 0 〜 n-1 の順に各要素が符号化されます。
可変長配列は次のように宣言します。
type-name identifier<m>;
または
type-name identifier<>;
定数 m は、配列に含まれる要素数の上限を示します。m を指定しないと、最大要素数は (2**32) - 1 とみなされます。
可変長配列

仕様で決められた最大要素数より大きな長さを符号化するとエラーになります。
構造体の構成要素は、構造体の宣言で並べた順に符号化されます。各構成要素のサイズはそれぞれ異なる可能性がありますが、各々が 4 の倍数に調整されます。
構造体は次のように宣言します。
struct {
component-declaration-A;
component-declaration-B;
...
} identifier;
構造体
識別型の共用体には、要素識別子に続いて、あらかじめ配置された一連のデータ型から要素識別子の値に応じて選択されたものが入ります。要素識別子のデータ型は、int、unsigned int、bool などの列挙型、のいずれかです。共用体の構成要素の型をアームといい、符号化を暗黙に示す要素識別子に続けて記述されます。
識別型の共用体は次のように宣言します。
union switch (discriminant-declaration) {
case discriminant-value-A:
arm-declaration-A;
case discriminant-value-B:
arm-declaration-B;
...
default:
default-declaration;
} identifier;
キーワード case の後には、要素識別子として指定できる値を書きます。デフォルトアームは省略できますが、その場合は要素識別子として定義されていない値を持つものを正しく符号化できません。各アームのサイズは、それぞれ 4 の倍数になります。
識別型の共用体は、要素識別子に続けて、それに対応するアームが符号化されます。
識別型の共用体

XDR の void 型は 0 バイトのデータです。void は、入力データまたは出力データを持たない操作を記述するときに使用します。また、共用体で、アームによってデータを持つものと持たないときがある場合にも使用できます。
void の宣言は次のように簡単です。
void;
const 型は定数を表すシンボル名を定義するのに使用しますが、データを宣言するものではありません。シンボル定数は、通常の定数を使用できるところならどこでも使用できます。
次の例では、12 を表すシンボル定数 DOZEN を定義します。
const DOZEN = 12;
定数は次のように宣言します。
const name-identifier = n;
typedef はデータを宣言するものではなく、新たな識別子でデータを宣言できるようにするためのものです。typedef の構文を次に示します。
typedef declaration;
typedef の宣言部分の変数名が、新たな型名になります。次の例では、既存の型 egg とシンボル定数 DOZEN を使用して、eggbox という新たな型を定義しています。
typedef egg eggbox[DOZEN];
新たな型名で宣言した変数は、typedef で変数として見た場合の型と同じ型を持ちます。したがって、次の 2 つの宣言は同じ型の変数 fresheggs: を宣言しています。
eggbox fresheggs; egg fresheggs[DOZEN];
typedef に struct、enum、union の定義が含まれるときは、同じ型を定義するのに、別のより望ましい構文が使用できます。一般に、typedef は次の形式で指定します。
typedef <<struct, union, or enum definition>> identifier;
この形式から typedef を取り去り、最後の識別子を struct、enum、union のキーワードの後に置くこともできます。bool 型を宣言する 2 つの方法を次に示します。
typedef enum {/* typedef を使用 */
FALSE = 0,
TRUE = 1
} bool;
enum bool {/* 望ましい方法 */
FALSE = 0,
TRUE = 1
};
最初の構文では宣言の最後まで見ないと新しい型名がわからないので、後の構文の方が望ましい方法です。
オプションデータは共用体の一種ですが、次のような特殊な構文を持ち、非常によく使用されます。次のように宣言されます。
type-name *identifier;
これは次のように宣言した共用体と同じです。
union switch (bool opted) {
case TRUE:
type-name element;
case FALSE:
void;
} identifier;
また、これは次のような可変長配列の宣言とも同じです。ブール型 opted は、配列の長さと解釈できるからです。
type-name identifier<1>;
オプションデータは再帰的データ構造体、たとえば、リンクリストやツリーの宣言に便利です。
この節では、XDR 言語を修正バッカス-ナウア記法で記述します。その表記規則を次に簡単に説明します。
特殊文字として、|、(、)、[、]、* を使用する
終端記号は、引用符 (") で囲んだ文字列または文字とする
非終端記号は、非特殊文字からなる文字列で、イタリックで表示する
代替項目は縦棒 (|) で区切って並べる
省略可能な項目は角括弧で囲む
項目をグループ化するときは、括弧で囲む
項目の後に * が付いている場合は、その項目の 0 回以上の繰り返しを表す
たとえば、次のパターンを考えてみます。
"a " "very" (", " " very")* [" cold " "and"] " rainy "
("day" | "night")
このパターンには、次の文字列を始めとして無数の文字列が一致します。
a very rainy day a very, very rainy day a very cold and rainy day a very, very, very cold and rainy night
空白は項目と項目の区切りに使用し、意味を持たない
任意の桁数の 10 進数を定数といい、始めに負符号 (-)を付けることができる
Syntax Information
declaration:
type-specifier identifier
| type-specifier identifier "[" value "]"
| type-specifier identifier "<" [ value ] ">"
| "opaque" identifier "[" value "]"
| "opaque" identifier "<" [ value ] ">"
| "string" identifier "<" [ value ] ">"
| type-specifier "*" identifier
| "void"
value:
constant
| identifier
type-specifier:
[ "unsigned" ] "int"
| [ "unsigned" ] "hyper"
| "float"
| "double"
| "quadruple"
| "bool"
| enum-type-spec
| struct-type-spec
| union-type-spec
| identifier
enum-type-spec:
"enum" enum-body
enum-body:
"{"
( identifier "=" value )
( "," identifier "=" value )*
"}"
struct-type-spec:
"struct" struct-body
struct-body:
"{"
( declaration ";" )
( declaration ";" )*
"}"
union-type-spec:
"union" union-body
union-body:
"switch" "(" declaration ")" "{"
( "case" value ":" declaration ";" )
( "case" value ":" declaration ";" )*
[ "default" ":" declaration ";" ]
"}"
constant-def:
"const" identifier "=" constant ";"
type-def:
"typedef" declaration ";"
| "enum" identifier enum-body ";"
| "struct" identifier struct-body ";"
| "union" identifier union-body ";"
definition:
type-def
| constant-def
specification:
definition *
|
次に示すものはキーワードとして予約されており、識別子として使用できない。
表 C-1 XDR キーワード|
|
|
|
|
|
|
|
|
cas |
default |
|
|
|
|
|
|
|
|
|
|
switch |
|
|
配列のサイズ指定に使用できるのは、符号なし定数だけである。識別子で指定するときは、その識別子をそれまでに const 定義を使用して符号なし定数として宣言しておく必要がある
同様に、構造体と共用体の宣言の有効範囲内では、変数名は一意的にする。構造体と共用体の宣言がネストしている場合は、新たな有効範囲ができる
共用体の要素識別子は、整数を表す型でなければならない。すなわち、int、unsigned int、bool、enum、または、このどれかの型を typedef で定義したものでなければならない。case で指定する値は、要素識別子の型に応じた値でなければならない。また、union 宣言の有効範囲内で case の値を 2 回以上指定してはならない
ファイルのデータ構造を XDR で記述した簡単な例を次に示します。このデータは、マシン間のファイル転送に使用することができます。
const MAXUSERNAME = 32;/* ユーザー名の最大長 */
const MAXFILELEN = 65535; /* ファイルの最大長 */
const MAXNAMELEN = 255; /* ファイル名の最大長 */
/* ファイルのタイプ */
enum filekind {
TEXT = 0, /* ASCII データ */
DATA = 1, /* raw データ */
EXEC = 2 /* 実行可能形式 */
};
/* ファイルタイプごとのファイル情報 */
union filetype switch (filekind kind) {
case TEXT:
void; /* その他の情報なし */
case DATA:
string creator<MAXNAMELEN>; /* データ作成者 */
case EXEC:
string interpreter<MAXNAMELEN>; /*プログラムインタプリタ*/
};
/* ファイル全体 */
struct file {
string filename<MAXNAMELEN>; /* ファイル名 */
filetype type; /* ファイル情報 */
string owner<MAXUSERNAME>; /* ファイルの所有者 */
opaque data<MAXFILELEN>; /* ファイルデータ*/
};
|
john というユーザーが、(quit) というデータだけが入った自分の LISP プログラム sillyprog を XDR 形式で保存するとします。このファイルは次のように符号化されます。
表 C-2 XDR データ記述の例|
オフセット |
バイト (16 進) |
ASCII |
説明 |
|---|---|---|---|
|
0 |
00 00 00 09 |
.... |
ファイル名の長さ = 9 |
|
4 |
73 69 6c 6c |
sill |
ファイル名の文字列 |
|
8 |
79 70 72 6f |
ypro |
ファイル名の文字列 (続き) |
|
12 |
67 00 00 00 |
g... |
ファイル名の文字列 (続き) と 3 バイトのヌルパディング |
|
16 |
00 00 00 02 |
.... |
ファイルタイプは EXEC = 2 |
|
20 |
00 00 00 04 |
.... |
インタプリタ名の長さ = 4 |
|
24 |
6c 69 73 70 |
lisp |
インタプリタの文字列 |
|
28 |
00 00 00 04 |
.... |
所有者名の長さ = 4 |
|
32 |
6a 6f 68 6e |
john |
所有者名 |
|
36 |
00 00 00 06 |
.... |
ファイルデータの長さ = 6 |
|
40 |
28 71 75 69 |
(qu |
ファイルデータ |
|
44 |
74 29 00 00 |
t).. |
ファイルデータ (続き) と 2 バイトのヌルパディング |
RPC 言語は XDR 言語を拡張したものです。唯一の拡張は program 型と version 型の追加です。
XDR 言語への RPC 拡張の説明については、 付録 B 「RPC プロトコルおよび言語の仕様」 を参照してください。
RPC 言語は C 言語と同様です。この節では、実際の例を示しながら RPC 言語の構文について説明します。また、RPC 型と XDR 型の定義が、出力ッダーファイル内で、どのように C 型の定義にコンパイルされるかについても説明します。
RPC 言語ファイルは以下の定義から構成されています。
definition-list: definition; definition; definition-list
また、RPC 言語ファイルは 6 つの型の定義を認めています。
definition: enum-definition const-definition typedef-definition struct-definition union-definition program-definition
定義は宣言と同じではありません。1 つまたは一連のデータ要素の型定義以外の定義によっては領域を割り当てることはできません。これは、変数は定義するだけでは十分でなく、宣言もする必要があることを意味しています。
RPC/XDR 列挙型の構文は、C 列挙型と同様です。
enum-definition:
"enum" enum-ident "{"
enum-value-list
"}"
enum-value-list:
enum-value
enum-value "," enum-value-list
enum-value:
enum-value-ident
enum-value-ident "=" value
XDR enum のコードと、それを C にコンパイルした結果の例を以下に示します。
enum colortype { enum colortype {
RED = 0, RED = 0,
GREEN = 1, --> GREEN = 1,
BLUE = 2 BLUE = 2,
}; };
typedef enum colortype colortype;
XDR シンボル定数は、整数定数が使用される場合は常に使用できます。たとえば、配列サイズを以下のように指定します。
const-definition: const const-ident = integer
次の例では、定数 DOZEN が 12 になるように定義します。
const DOZEN = 12; --> #define DOZEN 12
XDR typedef の構文は、C typedef と同様です。
typedef-definition: typedef declaration
次の例では、最大の長さが 255 文字のファイル名文字列を宣言するために使用される fname_type を定義しています。
typedef string fname_type<255>; --> typedef char *fname_type;
XDR には、4 種類の宣言があります。これらの宣言は、struct または typedef の一部でなければならず、単独では使用できません。
declaration: simple-declaration fixed-array-declaration variable-array-declaration pointer-declaration
単純な宣言は単純な C の宣言とほとんど同じです。
simple-declaration: type-ident variable-ident
例 :
colortype color; --> colortype color;
固定長配列宣言は C の配列宣言とほとんど同じです。
fixed-array-declaration: type-ident variable-ident [value]
例 :
colortype palette[8]; --> colortype palette[8];
多くのプログラマは、変数の宣言を型の宣言と混同します。rpcgen は変数の宣言をサポートしないことに注意することが重要です。以下に、コンパイルできないプログラムの例を示します。
int data[10];
program P {
version V {
int PROC(data) = 1;
} = 1;
} = 0x200000;
上記の例は、変数の宣言があるためにコンパイルできません。
int data[10]
int data[10] の代わりに、以下を使用してください。
typedef int data[10];
または
struct data {int dummy [10]};
C 言語には、可変長配列宣言の明示的な構文がありません。XDR 言語には、山括弧を使用する構文があります。
variable-array-declaration: type-ident variable-ident <value> type-ident variable-ident < >
最大のサイズは山括弧の間に指定されます。サイズを省略すると、配列が任意のサイズを持つということが示されます。
int heights<12>; /* 最大で 12 項目 */ int widths<>; /* 任意の数の項目 */
C では可変長配列の明示的な構文がないため、これらの宣言は struct 宣言にコンパイルされます。たとえば、heights 宣言は次の struct 宣言にコンパイルされます。
struct {
u_int heights_len; /* 配列の項目の数 */
int *heights_val; /* 配列へのポインタ */
} heights;
配列の項目の数は _len 構成要素に格納され、配列へのポインタは _val 構成要素に格納されます。各構成要素名の最初の部分は、宣言された XDR 変数 (heights) の名称と同様です。
ポインタ宣言は、C で行われる場合とまったく同様に XDR でも行われます。アドレスポインタは、実際にはネットワーク上に送信されないのに対して、XDR ポインタは、リストおよびツリーなどの再帰的なデータ型を送信するのに有効です。XDR 言語では、型は「ポインタ」ではなく、「オプショナルデータ」と呼ばれます。
pointer-declaration: type-ident *variable-ident
例 :
listitem *next; --> listitem *next;
RPC/XDR struct はその C の構造体とほとんど同じように宣言されます。宣言は以下のように行われます。
struct-definition:
struct struct-ident "{"
declaration-list
"}"
declaration-list:
declaration ";"
declaration ";" declaration-list
次に、二次元の座標である XDR 構造体と、その構造体がコンパイルされて生成される C 構造体の例を示します。
struct coord { struct coord {
int x; --> int x;
int y; int y;
}; };
typedef struct coord coord;
出力は、最後に追加された typedef を除いて入力と同一です。これによって、項目を宣言する際に、struct coord の代わりに coord を使用することができます。
XDR 共用体は識別された共用体であり、C 共用体には似ていません。XDR 共用体は Pascal 変形レコードに、より似ています。
union-definition:
"union" union-ident "switch" "("simple declaration")" "{"
case-list
"}"
case-list:
"case" value ":" declaration ";"
"case" value ":" declaration ";" case-list
"default" ":" declaration ";"
次に、「データの読み取り」操作の結果として返される型の例を示します。エラーがない場合はデータのブロックを返し、エラーが発生した場合は何も返しません。
union read_result switch (int errno) {
case 0:
opaque data[1024];
default:
void;
};
上記のコードは以下のようにコンパイルされます。
struct read_result {
int errno;
union {
char data[1024];
} read_result_u;
};
typedef struct read_result read_result;
出力 struct の共用体構成要素が、後に付いている _u を除いて型の名称と同じ名称であることに注意してください。
RPC プログラムは、次の構文を使用して宣言します。
program-definition:
"program" program-ident "{"
version-list
"}" "=" value;
version-list:
version ";"
version ";" version-list
version:
"version" version-ident "{"
procedure-list
"}" "=" value;
procedure-list:
procedure ";"
procedure ";" procedure-list
procedure:
type-ident procedure-ident "(" type-ident ")" "=" value;
-N オプションを指定すると、rpcgen は次の構文も認識します。
procedure:
type-ident procedure-ident "(" type-ident-list ")" "=" value;
type-ident-list:
type-ident
type-ident "," type-ident-list
たとえば以下のようになります。
/*
* time.x: 時間を取得するか、または設定してください。
* 時間は、1970 年 1 月 1 日 0:00 から経過した秒数で表されます。
*/
program TIMEPROG {
version TIMEVERS {
unsigned int TIMEGET(void) = 1;
void TIMESET(unsigned) = 2;
} = 1;
} = 0x20000044;
void 引き数型は、引数が渡されないことを意味していることに注意してください。
このファイルは、出力ヘッダーファイルの、以下の #define 文にコンパイルされます。
#define TIMEPROG 0x20000044 #define TIMEVERS 1 #define TIMEGET 1 #define TIMESET 2
RPC 言語規則には、いくつかの例外があります。
新しい機能の節で、rpcgen の C 形式モードの機能について説明しました。これらの機能は、void 引数に関連しています。引数の値が void である場合は、引数は渡される必要はありません。
C には組み込みのブール型はありません。しかし、RPC ライブラリは、TRUE または FALSE の、bool_t と呼ばれるブール型を使用します。XDR 言語でブール型として宣言されたパラメータは、出力ヘッダーファイルの bool_t にコンパイルされます。
例 :
bool married; --> bool_t married;
C 言語には組み込みの文字列型がありませんが、その代わりに、NULL で終了する char * 規則を使用します。C では、文字列は通常 NULL で終了する一次元の配列とみなされます。
XDR 語では、文字列は string キーワードを使用して宣言され、出力ッダーファイルの char * 型にコンパイルされます。山括弧の間で指定される最大サイズによって、文字列内で使用できる文字の最大数が指定されます (NULL 文字はカウントされない)。最大サイズを省略すると、任意の長さの文字列を指定できます。
例 :
string name<32>; --> char *name; string longname<>; --> char *longname;
NULL 文字列を渡すことはできません。ただし、長さが 0 の文字列 (すなわち、ターミネータまたは NULL バイト) を渡すことはできます。
XDR では、隠されたデータは、任意のバイトのシーケンスなどの、型のないデータを記述するために使用されます。隠されたデータは、固定長または可変長の配列として宣言することもできます。たとえば、以下のようになります。
opaque diskblock[512]; --> char diskblock[512];
opaque filedata<1024>; --> struct {
u_int filedata_len;
char *filedata_val;
} filedata;
void 宣言では、変数は指定されません。void 宣言には、void 以外何も記述しません。void 宣言は、共用体定義とプログラム定義の 2 つの部分で行うことができます (たとえば、引数を渡さない遠隔手続きの引き数または結果として)。