プログラミング言語SML#解説 4.1.0版
19 式

19.21 静的インポート式: _import ⟨string⟩ : ⟨cfunty⟩

C関数を直接SML#関数として使用するための式である. 構文の構成要素の意味は以下のとおりである.

  • •

    ⟨string⟩:C関数名. この名前が,リンク時にリンカによって外部名として参照される名前で ある.

  • •

    ⟨cfunty⟩:C関数の型の指定. 以下の文法に従い,C関数の型を指定する.

C関数型:⟨cfunty⟩
⟨cfunty⟩ ::= (⟨cfunattr⟩)?  ⟨argTyList⟩ -> ⟨retTyOpt⟩
⟨argTyList⟩ ::= ( ⟨argTy⟩,…,⟨argTy⟩ (,⟨varArgs⟩)? ) (複数引数)
 | ⟨argTy⟩ (引数がただ1つ)
 | () (引数なし)
⟨retTyOpt⟩ ::= ⟨retTy⟩
 | () (Cのvoid型に対応)
コールバック関数型:⟨argfunty⟩
⟨argfunty⟩ ::= (⟨cfunattr⟩)?  ⟨retTylist⟩ -> ⟨argTyOpt⟩
⟨retTyList⟩ ::= ( ⟨retTy⟩,…,⟨retTy⟩ (,⟨varRets⟩)? ) (複数引数)
 | ⟨retTy⟩ (引数がただ1つ)
 | () (引数なし)
⟨argTyOpt⟩ ::= ⟨argTy⟩
 | () (Cのvoid型に対応)
相互運用型:⟨interoperableTy⟩
⟨interoperableTy⟩ ::= (⟨tySeq⟩)? ⟨longTycon⟩ (Cと受け渡し可能な型に限る.以下に詳述)
SML#からCに渡す引数の型:⟨argTy⟩
⟨argTy⟩ ::= ⟨argTy⟩ * ⋯ * ⟨argTy⟩ (Cの構造体へのポインタ型に相当)
 | { ⟨argTyRow⟩ } (Cの構造体へのポインタ型に相当)
 | ⟨tyvar⟩ (boxedカインドを持つものに限る)
 | ⟨interoperableTy⟩
 | ⟨argfunty⟩ (コールバック関数引数型)
⟨argTyRow⟩ ::= ⟨lab⟩ : ⟨argTy⟩ (, ⟨argTyRow⟩)? (⟨lab⟩は⟨decimal⟩で始まるものに限る)
CからSML#に渡される返り値の型:⟨retTy⟩
⟨retTy⟩ ::= ⟨interoperableTy⟩
 | ⟨tyvar⟩ (boxedカインドを持つものに限る)
可変長引数型指定:⟨varArgs⟩および⟨varRets⟩
⟨varArgs⟩ ::= ... ( ⟨argTy⟩,…,⟨argTy⟩ )
⟨varRets⟩ ::= ... ( ⟨retTy⟩,…,⟨retTy⟩ )
C関数属性指定:⟨cfunattr⟩
⟨cfunattr⟩ ::= __attribute__((⟨attr⟩,…,⟨attr⟩))
⟨att⟩ ::= cdecl  | stdcall  | fastcc  | pure  | fast

C関数の型に現れる型名⟨interoperableTy⟩は, 以下の2つの条件を全て満たさなければならない.

  1. 1.

    ⟨interoperableTy⟩は以下のいずれかでなければならない.

    • •

      相互運用可能な原子型: int, int8, int16, int64, word, word8, word16, word64, real, real32, char, または string.

    • •

      Cポインタの型: codeptr, ⟨interoperableTy⟩ ptr, または unit ptr.

    • •

      多相Cポインタ型: ⟨tyvar⟩ ptr (ただし⟨tyvar⟩はboxedカインドまたはunboxedカインドを 持つものに限る).

    • •

      サイズ型: ⟨ty⟩ size.

    • •

      配列型: ⟨interoperableTy⟩ array, ⟨interoperableTy⟩ vector, または ⟨interoperableTy⟩ ref.

    • •

      多相配列型: ⟨tyvar⟩ array, ⟨tyvar⟩ vector, または ⟨tyvar⟩ ref (ただし⟨tyvar⟩はboxedカインドまたはunboxedカインドを 持つものに限る).

    • •

      type宣言で付けた,上記の型のいずれかの別名. (⟨tySeq⟩)? ⟨longTycon⟩を展開すると 上記のいずれかにならなければならない. ただし,⟨argTy⟩としての⟨interoperableTy⟩に type宣言で付けた型の別名が来た場合に限り, (⟨tySeq⟩)? ⟨longTycon⟩を展開した結果が ⟨argTy⟩相当の組型あるいはレコード型であっても良い.

  2. 2.

    CからSML#に渡されたり,Cが書き換えたりする可能性のある 値の型に,string型,array型,vector型,および ref型が現れてはならない. すなわち,これらの型は以下の箇所に現れてはならない.

    • •

      ⟨retTy⟩としての⟨interoperableTy⟩

    • •

      array,ref,およびptr型の型パラメタ

以上の条件を満たす⟨interoperableTy⟩は, その型名から自然に類推されるCの型に相当する. 対応を以下に示す.

⟨interoperableTy⟩ 対応するCの型
intおよびその仲間 同じサイズの符号付き整数型
wordおよびその仲間 同じサイズの符号付き整数型
real double
real32 float
char char
string const char *
codeptr Cの関数へのポインタ型
τ ptr τへのポインタの型
unit ptr void *または不完全型へのポインタ型
τ size size_t
τ array τ型の配列の先頭を指すポインタ型
τ vector τ型のconst配列の先頭を指すポインタ型
τ ref τ型の要素数1の配列を指すポインタ型

SML#のintおよびwordは常に 32ビットサイズの整数であることに注意されたい. 今日のほとんどのシステムでは SML#のintとCのintは対応するが, intが32ビットでないシステムではこれらは対応しない.

⟨argTy⟩の ⟨argTy1⟩ * ⋯ * ⟨argTyn⟩および {⟨lab1⟩:⟨argTy1⟩, ⋯, ⟨labn⟩:⟨argTyn⟩}型は, ⟨argTy1⟩, ⋯, ⟨argTyn⟩を ラベルの⟨decimal⟩の順番でメンバとして持つ const付き構造体型へのポインタに対応する. もし,全ての⟨argTyi⟩が同じならば, 要素数nの⟨argTyi⟩のconst付き配列の先頭への ポインタにも対応する.

C関数がSML#から見てパラメタ多相的に働くとき,かつ その場合に限り,C関数の引数および返り値の型として型変数を書いても良い. 例えば,Cの恒等関数

    void *id(void *x) { return x; }

を以下のようにインポートしてもよい.

    val ’a#boxed id = _import "id" : ’a -> ’a

また,任意のポインタの値を表示するprintf関数を 以下のようにインポートしてもよい.

    val ’a#boxed printPtr = _import "printf" : (string,...(’a)) -> int

C関数の型の前に記述する属性の意味は以下の通りである.

cdecl

ターゲットプラットフォーム標準のC関数呼び出し規約に従うC関数である ことを表す. 呼び出し規約に関する属性が指定されていない場合のデフォルトである.

stdcall

Windowsプラットフォームにおけるstdcall呼び出し規約に従うC関数である ことを表す.

fastcc

LLVMが提供するfastcc呼び出し規約に従うC関数であることを表す.

pure

C関数がSML#から見て純粋な関数であることを表す. すなわち,この属性を持つC関数は, メモリの書き換えを行わず,かつ引数リストのみから返り値がただ1つに定まる. SML#コンパイラの最適化に影響を与える.

fast

C関数が非常に短い時間で終了することを表す. この属性を持つC関数は, コールバック関数を通じてSML#のコードを呼び出したり, スレッドの実行を中断してはならない. SML#コンパイラは,この属性を持つC関数に対して,より 効率の良い呼び出しコードを生成する. ただし,この属性を持つC関数が長い時間を消費すると, GCに影響を与え,このC関数が終了するまでの間,全スレッドの実行が 止まる可能性がある.

この式の型は,⟨cfunty⟩で指定したC関数の型に対応する SML#の関数型である. 対応の定義は以下の通りである.

C関数型 SML#関数型
( ⟨argTy⟩1, …, ⟨argTy⟩n (⟨varArgs⟩)? ) -> ⟨retTy⟩ ⟨argTy⟩1 * ⋯ * ⟨argTy⟩n (* ⟨varArgs⟩)? -> ⟨retTy⟩

⟨argTyList⟩または⟨retTyOpt⟩が()の場合は, unit型としてSML#の型に現れる. ⟨interoperableTy⟩,⟨tyvar⟩,および⟨*⟩は そのままSML#の型に現れる. この定義は,コールバック関数型⟨argfunty⟩についても 同様である.

この式の値は,⟨string⟩で指定されたC関数を呼び出す SML#の関数である. C関数型の指定が正しい限り,通常のSML#関数として使用できる.