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.
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.
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の argTy * * argTyおよび {lab:argTy, , lab:argTy}型は, argTy, , argTyを ラベルのdecimalの順番でメンバとして持つ const付き構造体型へのポインタに対応する. もし,全てのargTyが同じならば, 要素数のargTyの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, , argTy varArgs ) -> retTy | argTy * * argTy * varArgs -> retTy |
argTyListまたはretTyOptが()の場合は, unit型としてSML#の型に現れる. interoperableTy,tyvar,および*は そのままSML#の型に現れる. この定義は,コールバック関数型argfuntyについても 同様である.
この式の値は,stringで指定されたC関数を呼び出す SML#の関数である. C関数型の指定が正しい限り,通常のSML#関数として使用できる.