我想使用tcl C API从C操作一个文件。在tcl内部,我会这样做:
% set file [open "my_file"]
file3
% myfunc::load $file
其中myfunc::load
来自C扩展:
#include <tcl/tcl.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#define NS "myfunc"
static int
Load_Cmd(ClientData cdata, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) {
if (objc != 2) {
Tcl_SetObjResult(interp,
Tcl_NewStringObj("wrong # args: should be \" " NS "::open file\"",
-1));
return TCL_ERROR;
}
Tcl_Obj *o = objv[1];
char *chan_name = Tcl_GetString(o);
Tcl_Channel chan = Tcl_GetChannel(interp, chan_name, NULL);
if (chan == NULL) {
return TCL_ERROR;
}
const Tcl_ChannelType * type = Tcl_GetChannelType(chan);
if (!strcmp(type->typeName, "file")) {
return TCL_ERROR;
}
return TCL_OK;
}
int DLLEXPORT
Myfunc_Init(Tcl_Interp *interp) {
Tcl_InitStubs(interp, TCL_VERSION, 0);
Tcl_CreateNamespace(interp, NS, NULL, NULL);
Tcl_CreateObjCommand(interp, NS "::load", Load_Cmd, NULL, NULL);
Tcl_PkgProvide(interp, "myfunc", "1.0");
return TCL_OK;
}
是否有方法获取与TCL频道关联的FILE
指针?
我尝试了以下方法:
FILE *data = Tcl_GetChannelInstanceData(chan);
FILE *fp = malloc(sizeof(FILE));
Tcl_GetChannelHandle(chan, TCL_READABLE, (ClientData *) fp);
FILE *fp = malloc(sizeof(FILE));
Tcl_GetOpenFile(interp, chan_name, /*forWriting=*/ 0, /*checkUsage=*/1, (ClientData *) fp);
但是这些似乎都不起作用并且以分段故障结束。e.
% myfunc::load $file
Segmentation fault (core dumped)
2条答案
按热度按时间qv7cva1a1#
Tcl不在任何平台上使用C stdio;stdio不太擅长处理异步I/O。相反,Tcl在任何可能的地方直接调用系统;在某些平台上,这可以避免一些非常讨厌的bug。
在所有POSIX平台(包括Linux和macOS)上,底层句柄实际上总是一个文件描述符,其类型为
int
。在Windows上,它可能是许多东西中的一个;通常是某种类型的HANDLE
,有时更复杂。***仅在POSIX平台上,***您还可以can do:
这有一个有点奇怪的类型签名;最后一个参数 should 是一个
FILE **
,但这并不是为了避免将大量的stdio直接绑定到Tcl的API中。Tcl在内部仍然不对通道使用FILE *
,但是在这种情况下,它会将文件描述符打包成一个(使用fdopen()
)。vbkedwbf2#
我假设有三种不同的方法来获取文件指针。我只有最后一个函数的信息,我认为这是对函数
Tcl_GetOpenFile
的手册页的误读你需要做的是:
...并且不要忘记检查函数的返回代码。如果你阅读了这个函数的源代码,那么你可以看到它的实现:
函数的最后一个参数:
void **filePtr
其被指定为:
*filePtr = f;
,其中f
是fdopen的结果。也就是说,它只是将
FILE *
分配给传入的内容。