Ch.9 SML#の拡張機能:Cとの直接連携

§ 9.2. C関数の型

SML#から利用可能なC関数は,SML#の型システムで表現 できる型を持つ関数です. _import宣言には,インポートするC関数の名前に加え,そのC関数の 型をMLライクな記法で記述します. val宣言で与えられた変数にはC関数が束縛されます. この変数の型は,C関数の型から生成されたSML#の関数型です. 以下,_import宣言に書くCの関数型の構文と,それに対応する MLの型のサマリを示します.

_import宣言には以下の形でC言語の関数の型を書きます.

(τ1, τ2, , τn) -> τ

これはn個のτ1,τ2,,τn型の引数を受け取り, τ型の値を返す関数を表します. 引数が1つの場合は引数リストの括弧を省略できます. 引数と返り値の型に何が書けるかは後述します. 関数が引数を何も受け取らない場合,引数リストの括弧だけを書きます.

() -> τ

関数が返り値を返さない場合(返り値の型がvoid型の場合), 返り値の型として()を指定します.

(τ1, τ2, , τn) -> ()

C関数が可変長の引数リストを持つ場合は以下の記法を使います.

(τ1, , τm, ...(τm+1, , τn)) -> τ

これは,m個の固定の引数とそれに続く0個以上の可変個の引数を取る関数の 型です. SML#は可変個の関数引数をサポートしていないため, 可変部分に与える引数のリストも指定する必要があります. この記法は,可変引数リストにτm+1,,τn型の引数を 与えることを表します.

C関数の引数および返り値の型には,Cの型に対応するSML#の型を 指定します. 以下,C関数の引数および返り値に書けるSML#の型を, 相互運用型と呼びます. 相互運用型には以下の型を含みます.

  • IntInfを除く全ての整数型.intwordcharなど.

  • 全ての浮動小数点数型.realReal32.realなど.

  • 要素の型が全て相互運用型であるような組型. int * real など.

  • 要素の型が相互運用型であるようなベクタ型,配列型,およびref型. stringWord8Array.arrayint refなど.

これら相互運用型とCの型の対応はおおよそ以下の通りです.

  • 整数型および浮動小数点数型の対応は以下の通りです.

    SML#の相互運用型 対応するCの型 備考
    char char Cのchar同様,符号は処理系に依存します
    Word8.word unsigned char 1バイトは8ビットであることを仮定します
    int int 処理系定義の自然な大きさの整数
    word unsigned int
    Real32.real float IEEE754形式の32ビット浮動小数点数を仮定します
    real double IEEE754形式の64ビット浮動小数点数を仮定します

  • τ vector型およびτ array型は, τ型に対応するCの型を要素型とする配列へのポインタ型に対応します. array型のポインタが指す先の配列はCから書き換えることができます. 一方,vector型のポインタが指す配列は書き換えることはできません. すなわち,vector型に対応するCのポインタ型には, ポインタが指す先のデータの型にconst修飾子が付きます.

  • string型はconst char型を要素型とする配列へのポインタ型に 対応します. このポインタが指す先の配列の最後には必ずヌル文字が入っています. 従って,SML#のstring型の値をCのヌル終端文字列への ポインタとして使用することができます.

  • τ ref型は,τ型に対応するCの型へのポインタ型に 対応します. ポインタが指す先には書き換え可能な長さ1の配列があります.

  • 組型τ1 * * τnは, τ1,,τnに対応する型のメンバーをこの順番で持つ 構造体へのポインタ型に対応します. このポインタが指す先の構造体はCから書き換えることはできません. τ1,,τnが全て同じ型ならば, その型を要素型とする配列へのポインタにも対応します.

C関数には,SML#の値がそのままの形で渡されます. C関数の呼び出しの際にデータ変換が行われることはありません. 従って,SML#で作った配列をC関数に渡し,C関数で変更し, その変更をSML#側で取り出すことができます.

C関数全体の型は,引数リストを組型とするMLの関数型に対応付けられます. ただし,C関数の引数や返り値に書ける相互運用型には,以下の制約があり ます.

  • 配列型や組型など,Cのポインタ型に対応する相互運用型を,C関数の返り値の 型として指定することはできません.