(13-1) [C&ML] C関数を対話型環境でテストする

[ トップ | 目次 | 前ページ | 次ページ ]


SML#からCの種々の関数を呼び出すステップは

  1. Cの関数のファイルtemp.cを作成する.
  2. gcc -shared -o ../lddLib/temp.dll temp.c
  3. temp.cの関数を呼び出すSMLソースファイルを作成する.

である.この3番目の標準手順を覚えておくと,Cの関数をMLと同様の気軽さでSML#の対話型環境から呼び出しテストすることができる.演習1の問1と問3で作成したの8つの関数

  1. power
  2. shou
  3. amari
  4. sigmaN
  5. sigmaN2
  6. A
  7. B
  8. C
  9. fib

を例に,その手順を学ぼう.以下,これら関数を含むファイルをex1.cとする.

SML#インタフェースファイルテンプレートの作成

Cの関数のインタフェイスファイルを作成する情報は,C関数にすべて含まれているので,Cの関数ファイルex1.cを作業用フォルダの作成と環境設定で作成したSML#のライブラリフォルダにex1.smlとしてコピーする.

関数ヘッダーの抜き出し

ex1.sml内容はCのコードである.これをSML#のインターフェイスコードに変換するために,Cの関数定義のヘッダ行以外をすべて消去する.本例の場合,以下のような内容となる.

int power(int n, int k) {
int shou(int x, int y) {
int amari(int x, int y) {
int sigmaN(int k, int n) {
int sigmaN2(int k, int n) {
int A(int a, int b, int n) {
int B(int a, int b, int n) {
int C(int a, int b, int c, int n) {
int fib (int n) {

動的ライブラリのオープン構文の作成

ファイルの先頭に以下のコードを作成する.

val dlName = "ex1.dll";
val dllLib = DynamicLink.dlopen(dlName);
fun bind fName = DynamicLinc.dlsym(dllLib,fname);

関数bindは,ライブラリから指定された関数名のポインタを取り出す関数である.

C関数ヘッダ行の変換

C関数ヘッダ行

type fname (type1 var1, ..., typen varn) {

を以下の形のSML#の束縛構文に変換する.

val fname = bind "fname" : _import (type1, ..., typen) -> type ;

Emacsになれた者は,置換とキーボードマクロ機能を使えば以下の手順で機械的に実現できる.

  1. { を -> で置き換える.
  2. 以下のキーボードマクロを定義
    1. 最初の行にカーソルを合わせる
    2. (キーボードマクロスタート)C-x (
    3. (カーソルを先頭に移動)C-a
    4. (帰り値型を末尾に移動)M-k C-e C-y
    5. (関数名をkill)C-a M-f M-f Mーb M-k
    6. (val宣言)M-k val C-y = bind " C-y " : _import
  3. (キーボードマクロ終了)C-x )

以上で,

type fname (type1 var1, ..., typen varn) {

val fname = bind "fname" : _import (type1 var1, ..., typen varn) -> type

の形に変換するキーボードマクロが定義される.ここキーボードマクロをC-xe で必用な回数呼び出せば,全ての行がこの形に変換される.これに続き,var1, ..., varnを消去すれば,SML#の動的ライブラリ束縛構文が得られる.

ファイルをセーブする.

本例では以下の内容のファイルex1.smlができる.

val dlName = "ex1.dll";
val dllLib = DynamicLink.dlopen(dlName);
fun bind fName = DynamicLink.dlsym(dllLib,fName);
val shou = bind "shou" : _import (int, int) -> int;
val amari = bind "amari" : _import (int, int) -> int;
val sigmaN = bind "sigmaN" : _import (int, int) -> int;
val sigmaN2 = bind "sigmaN2" : _import (int, int) -> int;
val  A = bind "A" : _import (int, int, int) -> int;
val B = bind "B" : _import (int, int, int) -> int;
val C = bind "C" : _import (int, int, int, int) ->  int;
val fib = bind "fib"  : _import (int) ->  int;

作成されたファイルはSML#のライブラリファイルに置かれるので,どこかれでも

use "ex1.sml";

以下のように文で参照できる.

c:\SMLSharpAndC\sml>smlsharp
smlsharp
SML# 0.30 (2007-07-03 16:16:12 JST)
# use "ex1.sml";
val dlName = "ex1.dll" : string
val dllLib = 0x10000000 : unit ptr
val bind = fn : string  -> unit ptr
val power = fn : int * int  -> int
val shou = fn : int * int  -> int
val amari = fn : int * int  -> int
val sigmaN = fn : int * int  -> int
val sigmaN2 = fn : int * int  -> int
val A = fn : int * int * int  -> int
val B = fn : int * int * int  -> int
val C = fn : int * int * int * int  -> int
val fib = fn : int  -> int
# power(2,3);
val it = 8 : int
# shou(23,7);
val it = 3 : int
# amari(23,7);
val it = 2 : int
# fib 10;
val it = 89 : int
#

ツールの利用

以上の手順を実行してみると理解される通り,機械的に作成できるのでこの手順を実行するツールを構築できる.近い将来そのようなツールを公開予定である.ツールを使えば,C関数が入ったファイル名を指定するだけで,その関数がSML#の対話環境から使用できるようになる.


[ トップ | 目次 | 前ページ | 次ページ ]

Last modified:2007/08/05 08:58:38
Keyword(s):
References:[ML&Cチュートリアル 目次] [(13) [C&ML] C関数をMLから呼び出す]