外部関数インターフェイス

HCl はCとの簡単な外部関数インターフェイス機能を持っています。実際に system:unix-argc,system:unix-argv, system:unix-getenvなどは このメカニズムによって実現されています。これらの関数はuser0.cに記述 されていますから、それを見ればfixnumを引数とする外部関数ならば容易 にインターフェイスできると思います。ユーザーが外部関数を定義するための 窓口としてuser1-4.cがmakefileに既に記述されているので、これらに関数を 定義し、トップレベルのmake(Makefile)を実行することによってCで記述された 関数を含むHCl が作られます。

Cで記述された関数の定義

HCl ではCで定義した関数を外部リンクした場合、イニシャライズを行うことに よってHCl から通常の関数と同じように見えるようにできます。 user0-4.cにはHCl がスタート時に一度呼び出すエントリ
user0_i,user1_i,user2_i,user3_i,user4_iが定義されています。 これらはfinit.srcが呼び出すものです。user?_iでは
init_xf("SYSTEM","UNIX-ARGC",ux_argc)
の形式でC関数とHCl 関数とが結合されますinit_xfの第一引数はlisp レベルの関数定義が属するパッケージ名、第二引数はlispレベルの関数名、 第三引数はCレベルの定義名です。この例ではCで定義されたux_argc がsystem:unix-argcというlisp関数となって現れます。

引数の受取り

Cで定義された関数がlispから呼び出された場合、その引数はlispオブジェクト のままでC関数に渡ります。渡された引数の個数を知る方法はありません (*) 。 HCl のオブジェクトとCのオブジェクトは内部表現が異なりますからC側での データ表現を得るためには簡単な処理が必要になります。詳細なデータ構造の 定義については{\tt doc/hclarch.doc}に内部表現の記述があるのでそれを 参考にして下さい。ここでは代表的な場合について簡単に説明します。
fixnum
fixnumの場合には実際の値はオブジェクトからオフセット 0xc8000000を引いたものとなります。このオフセット値はhcl2c.h中で FIXNUM_OFFSETとして 定義されています。
ux_argv(n)
OBJECT n;
{    int x;
     x = n - FIXNUM_OFFSET;
.........
}
	
この例ではnはlispオブジェクトのfixnumですがxはCでの同じ値の整数となります。
character
character objectをC側で受け取る場合は下位24bitのみ が意味を持ちます。従ってタグを取り去るマクロinf(x)を用いて 実際の値を取り出します。
charxmp(c)
OBJECT c;
{	char cc;
	cc = inf(c);
 .............
 }
	
double
double floatの場合は格納場所へのポインタがタグ付きで 渡されます。タグを取り去るマクロinf(x)を用いポインタを得、 それを用いて値を取り出します。
ux_dmy(n)
OBJECT n;
{    double *p,q;
     p = (double *)inf(n);
     q=*p;
    printf("\f",q)
.........
}
	
この例ではnはHCl のオブジェクトですがqはCのdoubleで同じ値を有します。
simple-string
simple-stringの場合にはHCl でのsimple-stringの内部表現を知る必要が あります。HCl でのsimple-stringはpointer+tagで表現されており、pointer を得るためにはまずオブジェクトからtagを剥す必要があります。このための マクロがinf(x)です。simple-stringの実体はCの構造体では次のように 定義されます。
struct HCL_STRING {int length;
                   char ch[SIZE];
                   }
	
ここでSIZEはlength分だけアロケートされています。Cとのインターフェースで 扱いにくいのは文字列の最後に0がセットされていない点です。従って Cプログラム上の文字列として取扱いたい場合には一旦バッファ領域にコピー する必要があります。
simple-vector
simple-vectorsimple-stringと同じく pointer+tagで表現されており、inf(x)でタグを取り去ったあとで simple-vectorの構造体へのポインタとして配列要素をアクセスします。 定義は次のようになっています。
struct HCL_VECTOR {int length;
                   OBJECT elt[SIZE];
                   }
	
ここでlengthは要素数の4倍であり、OBJECTはintと同じと考えていいです。

(*)MC88100版HClではC関数に渡せる引数の個数は最大8個に限定されます

C関数からの値の返し方

Cで記述した関数は1個の値のみを返すことができます。もっとも簡単な場合は nilを返す場合です。nilは内部では0x0で表現されていますので (return NIL)とすることによりそれを返すことが出来ます。

24bit以内の整数の場合はFIXNUM_OFFSETを加えることによってfixnumを作成し 返すことができます。それ以外の場合は一般に勧められません。どうしても 必要ならば副作用を用いるか、静的なオブジェクトの構造体を宣言しそこに 値の実体を格納しpointer+tagの形でオブジェクトを構成することによって stringやdouble floatを返すことができます。unix0.cにこのメカニズムによって 作成された関数、ux_argv,ux_getenvがありますので参考にして下さい。


Data General AViiON版の制限

MC88100をCPUとする版ではHCl から呼び出す外部関数の引数 の数は8以下に限定されます。 この制限は暫定的なもので将来は解決されます。 従ってX11のインターフェースでは一部の関数が8個以上の引数を取ります ので現在のDG AViiON版では使用できません。
もくじ