プログラミング言語SML#解説 4.1.0版
10 SML#の拡張機能:Cとの直接連携

10.1 C関数の使用の宣言

SML#からC言語で書かれた関数を呼び出すために必要なコードは, その関数の宣言のみです. 宣言は以下の文法で記述します.

val id = _import "symbol" : type

symbolは使用するC関数の名前,typeは その型の記述です. 型については次節で説明します. この宣言によって,SML#コンパイラは,C言語でコンパイルされ たライブラリやオブジェクトファイルの中の指定された名前を持つ関数をリンクし, SML#の変数idとして利用可能にします. リンク先のコードは,SML#が動作しているOSのシステム標 準の呼び出し規約に従っているものであれば,C言語以外でコンパイルされたもの でも構いません. このリンクはコンパイル時に行われます. 従って,この_import宣言を含むSML#プログラムをリンクする ときは,symbolをエクスポートするライブラリまたはオブジェクトファイル をSML#プログラムと共にリンクする必要があります. ただし,Cの標準ライブラリの一部(Unix系OSではlibc,libm)や pthreadライブラリに 含まれる関数は,それらライブラリはSML#コンパイラが常にリンクするため, リンクの指定無しに使用することができます.

この宣言は,val宣言を書けるところならどこに書くことができ ます. この宣言で定義されたSML#の変数idは, SML#で定義された関数と同様に使用することができます.

例えば,Cの標準ライブラリでは,以下の関数が提供されています.

int puts(char *);

この関数は,文字列を受け取り,その文字列と改行文字を標準出力に印 字し終了状態を返します. 終了状態は,正常なら印字した文字数,正常に印字できなかった場合は 整数定数EOF(具体的な値は処理系依存.Linuxでは-1)です. この型はSML#では,string -> int型に対応します. この関数を使用したい場合は,以下のように宣言します.

val puts = _import "puts" : string -> int

このように,_importキーワードの後にC言語関数の名前と型を 宣言するだけで,通常のML関数と同様に使用することができます. 以下は,対話型セッションでの宣言と利用の例です.

# val puts = _import "puts" : string -> int;
val puts = _ : string -> int
# puts "My first call to a C library";
My first call to a C library
val it = 29 : int
# map puts ["I","became","fully","operational","in","April","2nd","2012."];
I
became
fully
operational
in
April
2nd
2012.
val it = [2, 7, 6, 12, 3, 6, 4, 5] : int list

この例から理解されるとおり,インポートされたC関数も,MLプログラ ミングの原則「式は型が正しい限り自由に組み合わせることができる」に従い, SML#のプログラムで利用できます.