FFIの例:構造体を扱うC関数の呼び出し

32ビット整数(int型;long型)や64ビット浮動小数点データ(real型;double 型)などの原子データ以外に,それらを含む構造体も受け渡すことができる.ただし,構造体の場合,アラインメント(境界制約)は処理系依存である.そこで,SML#0.20版では,もっとも条件の強い以下のアラインメント処理を行っている.

  • realは8バイト境界に配置(必用に応じてバディングデータを挿入)
  • intは4バイト境界に配置
  • 1ワードへの文字や32ビット未満の整数のパックはサポートしない.

このアラインメント条件を満たすCの構造体へのポインタは,SML#の組み型に対応しており,受け渡すことができる.以下は構造体を受け取るCの関数例である.

 #include <stdio.h>
 typedef struct {double x; int y;} foo;
 typedef struct {int y; int padding; double x;} bar;
 int f (foo *a)
 {
   printf ("%g\n", (*a).x);
   printf ("%d\n", (*a).y);
   return (a->y + 1);
 }
 int g (bar *a)
 {
   printf ("%g\n", a->x);
   printf ("%d\n", a->y);
   return (a->y + 1);
 }

これら関数は,SML#から以下のような宣言を通じて使用することが出来る.

 val a = DynamicLink.dlopen "./struct.so";
 val fName = DynamicLink.dlsym(a, "f");
 val gName = DynamicLink.dlsym(a, "g");
 val f = fName : _import (real*int) -> int;
 val g = gName : _import (int*real) -> int;
 f (3.14,99);
 g (99,3.14);

SML#は以下のような結果を表示する.

 # use "struct.sml";
 val a = 0x083d8550 : unit ptr
 val fName = 0x45154724 : unit ptr
 val gName = 0x45154761 : unit ptr
 val f = fn : real * int  -> int
 val g = fn : int * real  -> int
 3.14
 99
 val it = 100 : int
 3.14
 99
 val it = 100 : int
 #

なお,将来は,SML#のシステム生成時に,アラインメント制約を,指定された現在のアーキテクチャでのCコンパイラに合わせることを計画している.

Last modified:2007/03/30 12:02:27
Keyword(s):
References:[Cとのシームレスな連携] [プログラミング例]