0
static int
MyReplacementExit(ClientData unused, Tcl_Interp *interp, int argc, const char *argv[])
{
 //     Tcl_DeleteInterp(interp);
 //     Tcl_Finalize();
        return TCL_OK;
}

int main() {
    Tcl_Interp *interp = Tcl_CreateInterp(); 
    Tcl_CreateCommand(interp, "exit", MyReplacementExit, NULL, NULL);

    Tcl_Eval(interp, "exit ; puts 11111111");
    std::cout << "22222222222" << std::endl;
    return 0;
}

exitTcl インタープリターのコマンド評価を処理する必要があります。デフォルトでは、それ自体を削除しようとし、std::exitプログラム全体を閉じる呼び出しも行います。それは私が望むものではないので、カスタム proc に置き換えようとしています。終了ハンドラー proc でインタープリターを削除する必要はありません (後で実行できます)。コマンドの後にexitコマンドの評価を続行しない場合にのみ必要です。

このコードではMyReplacementExit、何らかの方法で proc を変更する必要があるため、11111111印刷されませんが、印刷 22222222222されます。

TCL_ERRORこれは procから戻ることで実現できますがMyReplacementExit、他のエラー状況とこれを区別することはできません。

4

1 に答える 1

1

インタープリターを削除する代わりにexit(これにより、それ以上のコマンドの実行が停止されますが、データ構造がまだ使用されているため、実際にはすぐには削除されません)、重要なTcl_Evalことに、 への呼び出しをTcl_Preserveおよびへの呼び出しでラップしますTcl_ReleaseTcl_Finalize回避できる可能性がある場合は、電話しないでください。これは、Tcl ライブラリをメモリからアンロードしようとしているときに使用するもので、非常に扱いにくい場合があります (率直に言って、プロセスを終了する方が簡単です)。

コードでそれを行う方法は次のとおりです(適応):

static int
MyReplacementExit(ClientData unused, Tcl_Interp *interp, int argc, const char *argv[])
{
    Tcl_DeleteInterp(interp);  // <------------------
    return TCL_OK;
}

int main() {
    Tcl_Interp *interp = Tcl_CreateInterp(); 
    Tcl_CreateCommand(interp, "exit", MyReplacementExit, NULL, NULL);

    Tcl_Preserve(interp);      // <------------------
    Tcl_Eval(interp, "exit ; puts 11111111");
    Tcl_Release(interp);       // <------------------
    std::cout << "22222222222" << std::endl;
    return 0;
}

その時点でインタープリターが破壊されている可能性があるため (メモリが解放され、ランダムながらくたが走り書きされた場合など) 、インタープリターアクセスしないでください。結果を取得して使用する必要がある場合 (印刷など) は、事前に行ってください。Tcl_Release

この特定のケースでは、保存/解放のペアは必要ないことに注意してください。コードは実際にはインタープリターに触れていませんTcl_Eval(内部で独自の保持/解放を行います)。


インタープリターを終了させたくない場合、それはもっとトリッキーです。8.4 での最もクリーンな方法は、おそらくカスタム例外コード (つまり、 より大きいもの) をスローすることですが、Tcl のコマンドは引き続きトラップできるTCL_CONTINUEため、任意のコードに対して機能するという保証はありません。catch本当にそのような状況にある場合は、インタープリターを作成し、sub-interp で任意のコードを実行し、スクリプトの最後で破棄する方が実際には簡単です。その後、多くのコンテキストを失うことなく、そのインタープリターを削除できます。実際、次のことができます。

Tcl_Preserve(interp);
if (Tcl_Eval(interp, theScriptToEval) != TCL_OK)
    // Handle unexpected errors here
if (!Tcl_InterpDeleted(interp))
    Tcl_DeleteInterp(interp);
Tcl_Release(interp);

はい、これは、インタープリターをセットアップするために行う作業の量をかなり少なく保ちたいということを意味します。おそらく、割り込みでミリ秒ごとにこれを呼び出したいとは思わないでしょう…</p>

于 2013-04-29T09:21:37.470 に答える