我正在使用Tcl 8.6,我正在尝试做这样的事情来向tcl解释器添加函数
Tcl_Interp* interp,
void init() {
interp = Tcl_CreateInterp();
}
void add_tcl_function(char* cmd, function<int(int,char**)> F) {
obj2argv* o2a = new obj2argv;
auto lambda_proc = [&](
ClientData cdata,
Tcl_Interp* interp,
int objc,
Tcl_Obj* const objv[])
{
o2a->set(objc, objv);
F(objc, o2a->get_argv());
};
auto lamba_delete = [&](
delete o2a;
};
Tcl_CreateObjCommand(interp, cmd, lamda_proc, NULL, lamda_delete);
}
我想知道的是如何将“Tcl_Obj * const objv []”转换为“char ** argv”?
我在考虑创建一个类:
class obj2argv {
obj2argv();
void set(int objc, Tcl_Obj* const objv[]);
char** get_argv();
private:
//...
};
关于如何实现set()和get_argv()的任何想法?
有更简单的方法吗?
感谢。
obj2argv* o2a = new obj2argv;
答案 0 :(得分:2)
如果您正在为一个基本上与const char**
一起使用的函数连接参数,那么您应该使用Tcl_CreateCommand
注册该函数,并让Tcl为您处理字符串映射。它已经具备了所有必需的机制。
更正式地说,您正在处理具有此签名的粘合功能:
typedef int (Tcl_CmdProc) (ClientData clientData, Tcl_Interp *interp,
int argc, CONST84 char *argv[]);
CONST84
应该在所有新代码中被视为普通const
,而ClientData
是一个指针大小的值,Tcl只是动手并且从不检查(与您的相同)现有代码)。
如果您要自己进行映射,Tcl_GetString
将获取Tcl_Obj*
并返回char*
的表示形式。该表示通常应视为const
;由于历史原因,它并没有正式输入。
答案 1 :(得分:0)
我想补充一些信息:
我放弃使用lambda&#39; s因为当我添加捕获列表时,由于某种原因它不能将lambda转换为函数指针。所以我选择了传统方法(见下文)。除了:我仍然不知道为什么TCL文件说
typedef int Tcl_CmdProc(
ClientData clientData,
Tcl_Interp *interp,
int argc,
const char *argv[]);
但是编译器需要这个来编译:
typedef int Tcl_CmdProc(
ClientData clientData,
Tcl_Interp *interp,
int argc,
Tcl_Obj* const* argv);
守则:
int cmd_dispatch(
ClientData clientData,
Tcl_Interp* interp,
int argc,
Tcl_Obj* const* argv)
{
function<int(int,char**)> F = *(function<int(int,char**)>*)clientData;
return F(argc, (char**) argv); // <= CAST DOESN'T SEEM RIGHT
}
void cmd_delete(ClientData clientData)
{
}
void add_tcl_function(const char* cmd, function<int(int,char**)> F) {
Tcl_CreateObjCommand(interp, cmd, cmd_dispatch, (void*)&F, cmd_delete);
}
版本2:
struct cmd_data {
//Tcl_Interp* interp,
function<int(int,char**)> F;
int argc;
char* argv[MAX_ARGS];
};
int cmd_dispatch(
ClientData clientData,
Tcl_Interp* interp,
int argc,
Tcl_Obj* const* objv)
{
auto cmd_data1 = (struct cmd_data*) clientData;
cmd_data1->argc = argc;
for(int i=0; ((i < argc) && (i < MAX_ARGS)); i++) {
cmd_data1->argv[i] = Tcl_GetString(objv[i]);
// Who owns object returned by Tcl_GetString?
// memory leak? or invalid after return from function?
// garbage collected by tcl interp?
}
return cmd_data1->F(argc, cmd_data1->argv);
}
void cmd_delete(ClientData clientData)
{
auto cmd_data1 = (struct cmd_data*) clientData;
if (cmd_data1) {
delete cmd_data1;
}
}
void add_tcl_function(const char* cmd, function<int(int,char**)> F) {
auto cmd_data1 = new struct cmd_data;
cmd_data1->F = F;
Tcl_CreateObjCommand(interp, cmd, cmd_dispatch, (void*)cmd_data1, cmd_delete);
}
void init_tcl_commands() {
auto lambda_hello = [&](int argc ,char** argv) -> int {
cout << "HELLO WORLD!\n";
return 0;
};
tcl_backend::add_tcl_function("hello", lambda_hello);
}