ONC+ 開発ガイド

付録 C XDR プロトコル仕様

この付録では、XDR プロトコル言語の仕様について説明します。

XDR プロトコルの概要

外部データ表現 (external data representation: XDR) は、データの記述と符号化の標準規約です。XDR プロトコルは、異なるコンピュータアーキテクチャ間のデータ伝送に利用できます。これまで、SunTM WorkstationTM、VAX 、IBM PC、Cray など種々のマシン間のデータ通信に使用されてきました。XDR は、ISO の参照モデルのプレゼンテーション層 (第 6 層) に対応するもので、X.409 「ISO 抽象構文表記」におおむね従っています。XDR と X.409 との一番大きな違いは、XDR が暗黙的データ型を使用するのに対して、X.409 は明示的データ型を使用する点です。

XDR では、言語を使用してデータ形式を記述しますが、この言語はプログラミング言語ではないので、データの記述のためにだけしか使用できません。XDR 言語を使用すると、複雑なデータ形式も簡潔に表現できます。XDR 言語は C 言語に似ています。RPC や NFS のようなプロトコルでは、XDR でデータ形式を記述しています。

XDR 標準規約では、バイト (オクテット) は移植可能な 8 ビットデータとみなしています。

グラフィックボックス表現

この章では、データの説明や比較のときに、グラフィックボックス表現を使用します。ほとんどの場合、各ボックスが 1 バイトを表します。各バイトは 0n-1 で番号付けされます。データは、バイト m がバイト m+1 の直前に位置するという関係が保たれるバイトストリームで読み書きされます。データ項目はすべて 4 バイト (32 ビット) の倍数で表現されます。n バイトのデータの後には、0 〜 3 個の余分なゼロバイト r が付加されて、全体のバイト数が 4 の倍数になるように調整されます。ボックス間にある省略記号は、1 バイト以上の追加が必要が、またはまったく必要でないことを表します。次にその例を示します。

Graphic

基本ブロックサイズ

XDR のブロックサイズの選択はさまざまな条件の兼ね合いで決まります。2 のような小さな値を選択して符号化データを小さくすると、そのようなデータ境界を使用しないマシンでは整合の問題が起こります。8 のような大きな値にすると、事実上すべてのマシンでデータ整合が可能になりますが、符号化データが大きくなり過ぎます。妥協案として 4 が選ばれました。4 は適度な大きさでほとんどのアーキテクチャに対応できますが、8 バイト境界の Cray などのマシンは例外です。

ただし Cray コンピュータで標準 XDR が使用できないわけではありません。各データ項目のオーバヘッドが、4 バイト (32 ビット) アーキテクチャのマシンより大きくなるという意味です。4 という値は符号化データを妥当なサイズに押さえる意味でも適当な値です。

どのマシンでも同じデータは同じ値に符号化されなければ、符号化データを比較したりチェックサムを取ったりできません。したがって、可変長データの最後は、ゼロデータでパディングしなければなりません。

XDR のデータ型宣言

以降の各節は次の部分に分れています。

XDR 言語で使用できる各データ型の宣言方法を示します。大小記号による括弧 (<>) は可変長のデータシーケンスを示し、角括弧 [])は固定長のデータシーケンスを示します。nmr は整数を表します。XDR 言語の詳細仕様については、「XDR 言語仕様」の節を参照してください。

いくつかのデータ型については、具体的なデータ記述例も示します。より詳しいデータ記述例については、「XDR データ記述 」を参照してください。

符号付き整数

説明

XDR の符号付き整数は、[-2147483648, 2147483647] の範囲の整数が符号化された 32 ビットデータです。整数は 2 の補数で表されます。最上位バイト (MSB) と最下位バイト (LSB) はそれぞれバイト 0 とバイト 3 です。

宣言

整数は次のように宣言します。

int identifier;

符号化

整数

Graphic

符号なし整数

説明

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

宣言

符号なし整数は次のように宣言します。

unsigned int identifier;

符号化

符号なし整数

Graphic

列挙型

説明

列挙型のデータ表現方法は符号付き整数と同じです。列挙型は、整数のサブセットを記述するのに便利です。

宣言

列挙型は次のように宣言します。

enum {name-identifier = constant , ... } identifier;

たとえば、列挙型を使用して赤、黄、青の 3 色を次のように表すことができます。

enum {RED = 2, YELLOW = 3, BLUE = 5} colors;

列挙型に、enum 宣言で指定されていない整数を代入しようとするとエラーになります。

符号化

「符号付き整数」を参照してください。

ブール型

説明

ブール型は、標準規約の明示型に対応するための型で、よく使用される重要なデータ型です。ブール型には、整数の 01 を使用します。

宣言

ブール型は次のように宣言します。

bool identifier;

これは、次の宣言と同じです。

enum {FALSE = 0, TRUE = 1} identifier;

符号化

「符号付き整数」を参照してください。

hyper 整数と符号なし hyper 整数

説明

標準規約では 64 ビット (8 バイト) の整数として hyper intunsigned hyper int を定義しています。その表現方法は明らかに、上で説明した integerunsigned integer を拡張したものです。hyper 整数は 2 の補数で表されます。最上位バイト (MSB) と最下位バイト (LSB) はそれぞれバイト 0 とバイト 7 です。

宣言

Hyper 整数は次のように宣言します。

hyper int identifier;
unsigned hyper int identifier;  

符号化

Hyper 整数

Graphic

浮動小数点

説明

標準規約では、浮動小数点型 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; 

符号化

倍精度浮動小数点

Graphic

整数の最上位バイトと最下位バイトがバイト 0 とバイト 3 であるのと同様に、倍精度浮動小数点型の値の最上位ビットと最下位ビットはビット 0 とビット 63 になります。S、E、F の各フィールドの開始ビット (最上位ビット) のオフセットはそれぞれ 0、1、12 になります。

これらのオフセットは論理的ビット位置を示すもので、物理的位置を示すものではありません (物理的位置は媒体によって異なります)。

符号付きゼロ、符号付き無限大 (オーバフロー)、正規化されない値 (アンダフロー) の符号化については、IEEE 標準規約 [1] を参照してください。IEEE 標準規約によると、NaN (not a number) は、システムごとに異なるため外部表現では使用できません。

4 倍精度浮動小数点

説明

標準規約では、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 倍精度浮動小数点

Graphic

整数の最上位バイトと最下位バイトがバイト 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 の倍数になるように調整されます。

固定長の隠されたデータ

Graphic

可変長の隠されたデータ

説明

標準規約では、可変長 (カウント付き) の隠されたデータも次のように定義されています。n バイトの任意のバイトシーケンス(バイト番号は 0n-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>;

符号化

可変長の隠されたデータ

Graphic

指定した最大バイト数以上の長さを符号化するとエラーになります。

カウント付きバイト文字列

説明

標準規約では、n バイトの ASCII 文字列 (バイト番号は 0n-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>;

符号化

文字列

Graphic

指定した最大バイト数以上の長さを符号化するとエラーになります。

固定長配列

固定長配列の要素番号は 0n-1 で、個々の配列要素が 0n-1 の番号順に符号化されます。各配列要素のバイト数は 4 の倍数になっています。全要素が同一のデータ型であっても、要素のサイズが異なることがあります。たとえば、文字列の固定長配列の場合、要素のデータ型はすべて string 型ですが、個々の要素の長さは異なります。

宣言

各要素のデータ型がすべて同じである固定長配列は、次のように宣言します。

type-name identifier[n];

符号化

固定長配列

Graphic

可変長配列

説明

可変長配列をカウント付きで符号化することによって、固定長の要素と同じように符号化できます。要素カウント n (符号なし整数) に続けて、要素番号 0n-1 の順に各要素が符号化されます。

宣言

可変長配列は次のように宣言します。

type-name identifier<m>; 

または

type-name identifier<>;

定数 m は、配列に含まれる要素数の上限を示します。m を指定しないと、最大要素数は (2**32) - 1 とみなされます。

符号化

可変長配列

Graphic

仕様で決められた最大要素数より大きな長さを符号化するとエラーになります。

構造体

説明

構造体の構成要素は、構造体の宣言で並べた順に符号化されます。各構成要素のサイズはそれぞれ異なる可能性がありますが、各々が 4 の倍数に調整されます。

宣言

構造体は次のように宣言します。

struct {
  	component-declaration-A;
  	component-declaration-B;
  	...
 } identifier;

符号化

構造体

Graphic

識別型の共用体

説明

識別型の共用体には、要素識別子に続いて、あらかじめ配置された一連のデータ型から要素識別子の値に応じて選択されたものが入ります。要素識別子のデータ型は、intunsigned intbool などの列挙型、のいずれかです。共用体の構成要素の型をアームといい、符号化を暗黙に示す要素識別子に続けて記述されます。

宣言

識別型の共用体は次のように宣言します。

union switch (discriminant-declaration) {
  	case discriminant-value-A:
  		arm-declaration-A;
  	case discriminant-value-B:
  		arm-declaration-B;
  	...
  	default:
  		default-declaration;
 } identifier; 

キーワード case の後には、要素識別子として指定できる値を書きます。デフォルトアームは省略できますが、その場合は要素識別子として定義されていない値を持つものを正しく符号化できません。各アームのサイズは、それぞれ 4 の倍数になります。

識別型の共用体は、要素識別子に続けて、それに対応するアームが符号化されます。

符号化

識別型の共用体

Graphic

Void

説明

XDR の void 型は 0 バイトのデータです。void は、入力データまたは出力データを持たない操作を記述するときに使用します。また、共用体で、アームによってデータを持つものと持たないときがある場合にも使用できます。

宣言

void の宣言は次のように簡単です。

void; 

定数

説明

const 型は定数を表すシンボル名を定義するのに使用しますが、データを宣言するものではありません。シンボル定数は、通常の定数を使用できるところならどこでも使用できます。

次の例では、12 を表すシンボル定数 DOZEN を定義します。

const DOZEN = 12;

宣言

定数は次のように宣言します。

const name-identifier = n;

Typedef

typedef はデータを宣言するものではなく、新たな識別子でデータを宣言できるようにするためのものです。typedef の構文を次に示します。

typedef declaration;

typedef の宣言部分の変数名が、新たな型名になります。次の例では、既存の型 egg とシンボル定数 DOZEN を使用して、eggbox という新たな型を定義しています。

typedef egg eggbox[DOZEN];

新たな型名で宣言した変数は、typedef で変数として見た場合の型と同じ型を持ちます。したがって、次の 2 つの宣言は同じ型の変数 fresheggs: を宣言しています。

eggbox fresheggs;
 egg fresheggs[DOZEN];

typedefstructenumunion の定義が含まれるときは、同じ型を定義するのに、別のより望ましい構文が使用できます。一般に、typedef は次の形式で指定します。

typedef <<struct, union, or enum definition>> identifier;

この形式から typedef を取り去り、最後の識別子を structenumunion のキーワードの後に置くこともできます。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 言語仕様

表記方法

この節では、XDR 言語を修正バッカス-ナウア記法で記述します。その表記規則を次に簡単に説明します。

  1. 特殊文字として、|()[]* を使用する。

  2. 終端記号は、引用符 (") で囲んだ文字列または文字とする。

  3. 非終端記号は、非特殊文字からなる文字列で、イタリックで表示する。

  4. 代替項目は縦棒 (|) で区切って並べる。

  5. 省略可能な項目は角括弧で囲む。

  6. 項目をグループ化するときは、括弧で囲む。

  7. 項目の後に * が付いている場合は、その項目の 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

字句解析ノート

  1. コメントは、/**/ で囲む。

  2. 空白は項目と項目の区切りに使用し、意味を持たない。

  3. 識別子は英字で始まり、英字、数字、下線 (_) を含むことができる。識別子では、大文字と小文字を区別する。

  4. 任意の桁数の 10 進数を定数といい、始めに負符号 (-)を付けることができる。


    例 C-1 XDR 仕様

    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 *
     

構文ノート

  1. 次に示すものはキーワードとして予約されており、識別子として使用できない。

    表 C-1 XDR キーワード

    bool

    const

    enum

    int

    string

    typedef

    void

    cas

    default

    float

    opaque

    struct

    union

     

    cha

    double

    hyper

    quadruple

    switch

    unsigned

     

  1. 配列のサイズ指定に使用できるのは、符号なし定数だけである。識別子で指定するときは、その識別子をそれまでに const 定義を使用して符号なし定数として宣言しておく必要がある。

  2. 指定範囲内の識別子の定数と型は、同じ名前空間内にあり、この範囲内で一意に宣言されていなくてはなりません。

  3. 同様に、構造体と共用体の宣言の有効範囲内では、変数名が一意的に決まらなければならない。構造体と共用体の宣言がネストしている場合は、新たな有効範囲ができる。

  4. 共用体の要素識別子は、整数を表す型でなければならない。すなわち、intunsigned intboolenum、または、このどれかの型を typedef で定義したものでなければならない。case で指定する値は、要素識別子の型に応じた値でなければならない。また、union 宣言の有効範囲内で case の値を 2 回以上指定してはならない。

XDR データ記述

ファイルのデータ構造を XDR で記述した簡単な例を次に示します。このデータは、マシン間のファイル転送に使用することができます。


例 C-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 interpretor<MAXNAMELEN>; /*プログラムインタプリタ*/
};
 
/* ファイル全体 */
struct file {
 	string filename<MAXNAMELEN>;        /* ファイル名 */
 	filetype type;                      /* ファイル情報 */
 	string owner<MAXUSERNAME>;          /* ファイルの所有者 */
 	opaque data<MAXFILELEN>;            /* ファイルデータ*/
};

john というユーザーが、(quit) というデータだけが入った自分の LISP プログラム sillyprog を XDR 形式で保存するとします。このファイルは次のように符号化されます。

表 C-2 XDR データ記述の例

オフセット 

バイト (16 進) 

ASCII 

説明 

00 00 00 09 

.... 

ファイル名の長さ = 9 

73 69 6c 6c 

sill 

ファイル名の文字列 

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 言語リファレンス

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 

次の例では、定数 DOZEN12 になるように定義します。

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 言語規則には、いくつかの例外があります。

C 形式モード

新しい機能の節で、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;

Voids

void 宣言では、変数は指定されません。void 宣言には、void 以外何も記述しません。void 宣言は、共用体定義とプログラム定義の 2 つの部分で行うことができます (たとえば、引数を渡さない遠隔手続きの引き数または結果として)。