多相型Cライブラリ関数qsort(3)の呼び出し

C言語のライブラリ関数qsort(3)も,fread(3)同様の多相関数である.マニュアルによれば,その型は以下の通りである.

 void qsort(void *base, size_t nmemb, size_t size,
            int(*compar)(const void *, const void *));

各引数の意味は以下の通りである.

  • voild *base:ソート対象配列
  • size_t nmemb :配列の要素の数
  • size_t size :配列の要素のサイズ
  • int(*compar)(const void *, const void *):要素へのポインタの組みを受け取る比較関数

MLのような型付き多相型言語では以下のような関数として使用できるのが望ましい.

qsort : 'a array * ('a ptr * 'a ptr -> int) -> unit

ここで,'a ptrはCの空間にある'a型へのポインタである.SML#では,コールバック機能freadの場合 と同様の考え方を使い,以下のように使用することができる.

 val libc = DynamicLink.dlopen "/lib/libc.so.6"
 val c_qsort = DynamicLink.dlsym (libc, "qsort")
 fun qsort (a, f) =
     _ffiapply c_qsort (a : 'a array,
                        Array.length a : int,
                        _sizeof('a),
                        f : ('a ptr, 'a ptr) -> int) : unit

この式をSML#で評価すると,実際に

val qsort = fn : ['a .'a Array.array * ('a ptr * 'a ptr  -> int)  -> unit]

の結果が得られる.この関数を使用するためには,Cの領域にあるオブジェクトの比較関数を定義する必用がある.そのために,以下の多重定義関数が用意されている.

!! : ['a::{int, real, word, byte, char}.'a ptr -> 'a]

これを使い,たとえば以下のように呼び出すことができる.

 fun compareReal (p1, p2) =
     let
       val n1 = !!p1 : real
       val n2 = !!p2
     in
       if n1 > n2 then 1 else if n1 < n2 then ~1 else 0
     end
 val _ = qsort (aRealArray, compareReal)
Last modified:2007/04/03 13:01:27
Keyword(s):
References:[プログラミング例]