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_ERRORMyReplacementExitproc返回来实现,但是我无法区分其他错误情况。

4

1 回答 1

1

替换exitdelete 解释器(它会停止执行进一步的命令,但实际上并不会立即删除仍在使用的数据结构),并且重要的是,将调用包装到对和的Tcl_Eval调用。如果可以避免,请不要打电话;这适用于您即将从内存中卸载 Tcl 库并且可能非常棘手(坦率地说,退出该过程更容易)。Tcl_PreserveTcl_ReleaseTcl_Finalize

以下是如何使用您的代码(改编):

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_CONTINUE),但不能保证它适用于任意代码,因为 Tcl 的catch命令仍然可以捕获它。如果你真的遇到这种情况,实际上更容易创建一个解释器,在子解释器中运行任意代码,然后在脚本结束时将其删除;然后,您可以删除该解释器而不会丢失太多上下文。事实上,你可以这样做:

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 回答