● 関数リファレンス
コールバック関数MFUNC
double __stdcall function(double *arg,int argcnt,int *pret,void *param)
{
return 計算結果;
}
引数
引数名 | 意味 |
arg | 関数の引数。記述されている左側から順に arg [0] 、arg [1] 、arg [2] … となります。 |
argcnt | 引数の個数(arg の全要素数)。 |
pret | 状態コードを返すための int型領域のアドレスが渡されます。 |
param | 追加パラメータ。関数StrCalc_setfunc の 5 番目の引数がそのまま渡されます。 |
説明
ユーザ定義の数学関数を処理するコールバック関数です。関数ポインタの型は sc39.h 内で定義されています。
typedef double (__stdcall *MFUNC)(double *,int ,int *,void *);
関数が正常終了した時は STATUS_NORMAL をpret の指す領域に格納し、計算結果を戻り値で返してください。
例. 引数をインクリメントし、結果を返す
double __stdcall user_f_inc(double *arg,int argcnt,int *pret,void *param)
)
{
*pret = STATUS_NORMAL;
return arg[0] + 1;
}
それ以外の場合は状態コードを pret に返してください。STATUS_NORMAL 以外の場合は、戻り値は無視されます。
適当なコードが見つからなければ、アプリケーション独自のコードを作成しても問題ありませんが、その場合は STATUS_NORMAL 未満の値(負の値)を使用してください。
注意点
- 関数内部で StrCalc系関数を使用する事は可能ですが、処理中の STRCALC_PARAM 構造体の実体を、コールバック関数内(数学関数内)で直接、計算処理に使用しないでください。
STRCALC_PARAM 構造体には計算過程を管理する情報も含まれており、StrCalc の計算系関数で使用すると内容が更新されてしまうので、コールバック関数から戻った時に、予測不能の挙動をする可能性があります。
コールバック関数内で文字列の計算を行う方法 @
double __stdcall user_test(
double *arg,
int argcnt,
int *pret,
PSTRCALC_PARAM p_orgprm)
{
STRCALC_PARAM prm;
/* このコールバック関数内だけで有効な新しい環境を作成する */
if (!StrCalc_init(&prm)){
*pret = STATUS_NOTENOUGHMEM;
return 0.0;
}
/*
呼び出し元から継承する情報がある場合は、
ここでセットします。
*/
prm.str = 計算式;
*pret = StrCalc(&prm);
StrCalc_term(&prm);
return prm.ans;
}
この例では、追加パラメータに呼び出し元環境の先頭アドレスを渡していると仮定します。
上記 @ は、コールバック内で新規に環境を作成する方法です。安全な方法ですが、パフォーマンスがあまり良くありません。
コールバック関数内で文字列の計算を行う方法 A
double __stdcall user_test(
double *arg,
int argcnt,
int *pret,
PSTRCALC_PARAM p_orgprm)
{
STRCALC_PARAM prm = *p_orgprm;
prm.str = 計算式;
*pret = StrCalc(&prm);
/* ここでは local に対して StrCalc_term を使用してはなりません */
return prm.ans;
}
A は呼び出し元の環境をローカルにコピーし、写した方を使用します。StrCalc_init / StrCalc_term を省けるので効率的ですが、変数環境の変化に注意を払う必要があります。
処理で変数環境が変わらない場合は、使用した情報を破棄すればOKです。変数環境が変わる処理を行った場合は、関数StrCalc_copy_paraminfo により、呼び出し元環境に反映させる必要があります。
プログラム例(zip)
- 関数内で StrCalc による再帰的な計算を行わせる事は可能です(この場合の再帰は、ユーザ関数内で自分自身の関数を使用した計算式文字列を処理する事)。しかし、どのような形で計算式が与えられるか予測が難しい場合は、安全性の面で推奨しません。
例.循環を禁止する(シングルスレッドの場合)
double __stdcall user_func(double *arg,int argcnt,int *pret,void *param)
)
{
static int b_active;
/*
b_active ≠ 0 の場合は処理の中で
自分自身の関数を実行しようとした
*/
if (b_active){
*pret = エラーコード
b_active = 0; /* 次回のためクリアしておく */
return 0.0;
}
b_active = 1; /* 計算処理開始 */
・
・
・
b_active = 0; /* 計算処理終了 */
*pret = STATUS_NORMAL;
return ans;
}