I need a help with passing pointers to my extension library written in
C++. The library uses pointers for data exchange and I need pure C
pointer to indicate e.g. where to write to/read from. How should I
handle them? Do I need additional functionalities in C API or can I
use some of the standard functions?
I know that SWIG fully supports pointers even for functions so it is
possible to invoke callbacks from TCL side in C.
Any help will be appreciated.
Best regards,
Twister
One simple solution is to sprintf/sscanf the pointer with %p format to/
from a string, and give that to Tcl. Whether the pointer is still
valid needs of course to be ensured, if you don't want to risk
segmentation faults...
Hello Twister,
within a C extension (e.g. a custom command implemended in a loadable
library),
you may use the following sequence to get a pointer on data passed as
an argument:
p = Tcl_GetByteArrayFromObj(argv[0], &length);
To return a byte data set by a pointer, you may use:
TCL_OBJ * po;
po = Tcl_NewByteArrayObj(p,length);
Tcl_SetObjResult(interp, po);
If your data are utf8-strings, you may use string functions instead
the byte array functions.
If you do not have any commands and you want, in a sort, modify
variables directly, you may execute commands if you have the interp
pointer on the c side.
You may also read and set global variables.
Hope this helps,
Harald
Thanks to both of you for quick reply. The Harald idea solves one of
my problem perfectly. The other question is how to pass a pointer for
function. Some workaround I am thinking of is to use Tcl_EvalObj() but
then I have to pass also variables as arguments for that function. Is
there a possibility to create kind of callback using C Api?
Oh, I thought I was quite off-topic.
To post an event to the TCL event loop, please look at the command
Tcl_CreateEventSource and its wiki page:
http://wiki.tcl.tk/17195
Hope this helps,
Harald
There are a number of different ways to do this. If you can package
all the information that you want to pass into a 'struct' *and* you
don't need stable pointers/references to the data from the C++ side,
then you can pass the struct through Tcl as a chunk of uninterpreted
bytes using the Tcl_NewByteArrayObj and Tcl_GetByteArrayFromObj
functions. (It's up to you whether you put the Tcl_Obj handles in
variables or pass through the Tcl interpreter result/argument
mechanism.)
> I know that SWIG fully supports pointers even for functions so it is
> possible to invoke callbacks from TCL side in C.
That's a bit more complex. When you're doing callbacks, you *do* need
stable pointers/references. In that case, the standard way involves
still putting everything in a 'struct' (for simplicity if nothing
else) but then storing a pointer to the struct in a Tcl_HashTable with
some arbitrary string handle (e.g. the printed form of the pointer or
a counter, all possibly with some "type" string prefix so they're
easier to recognize from a script). You can then pass the string
handle about with total impunity; any time you need the actual data,
you can just look it up. (There are variations on this basic
technique; for example, a Tcl command is really this sort of thing
with a few extra details...) For more info, take a look at http://wiki.tcl.tk/1089
That's really the two directions that your solution will lie in. Do
keep asking so that we can help you to the solution for your needs.
Donal.
Hello Donal
Thanks for joining my thread. My problem now is to get somehow on C/C+
+ side the pointer to function (from TCL) I will invoke later. As I
wrote earlier the pointer to buffer I can get with
Tcl_GetByteArrayFromObj and that is not a problem any more. In case of
pointers to function passing all by the 'struct' probably will due but
I was thinking about what preserve me from passing also (except name
of proc) the variables as arguments for proc. The ideal would be if I
could convert the TCL handle into pure pointer to function in C/C++.
What is your opinion about that? And what solution you think is the
best?
Best regards,
Twister
It's possible that your best bet for doing that is to put the pointer
(plus any extra bits and pieces required for calling it) in a structure
and to use the hash table mapping technique talked about above
<URL:http://wiki.tcl.tk/1089> since that's both safe and powerful. You
can even do things like pointers to virtual methods, (effectively)
prebound arguments[*], and stuff like that. The other advantage of the
use of a hash table/handle approach is that it gives you safety: your
Tcl code cannot synthesize an invalid pointer. (Yes, you have to be
careful with destructors. That's normal for any sophisticated scheme...)
The down-side of this is that it can take a lot of computation to deal
with the handles when you have a lot of them. If you've only got a few
thousand at any time, this isn't a big issue.
Does this help you answer your question?
Donal.
[* Tcl commands have a ClientData parameter, which is definitely very
much like a prebound argument. ]
Could you give me a simple example? To be honest I can't imagine
passing that pointer. How should the function (with callback as
argument) be invoked from Tcl script?
Best regards,
Twister
A simple example? Hmm, tricky because the amount of code starts to get
large. You'll need the C code from http://wiki.tcl.tk/1089 to start
out with; that's a bit longer than I want to retype.
Then, when your C (or C++) code wants to hand off a pointer through
Tcl, it should convert it to a handle using a suitable call (e.g.
GetObjForPointer from the wiki page) which will generate a handle that
you can then pass to Tcl. Once the handle comes back to your C/C++
code, you can then convert it back to a pointer using
GetPointerForObj, which safely reverses the process. (The wiki page
should explain how to use the functions, and the patterns aren't that
unusual for anyone who has used the Tcl C API...)
Be careful with pointers to C++ methods; they are quite probably not
the same size as C pointers. This can be fixed by not using the
generic mechanism from the wiki page and instead nailing it down to
work with a specific pointer type. (I suppose that code could even be
templated and made more useful to C++ users, but my C++ skills are
inadequate to that.)
Donal.
> Then, when your C (or C++) code wants to hand off a pointer through
> Tcl, it should convert it to a handle using a suitable call (e.g.
> GetObjForPointer from the wiki page) which will generate a handle that
> you can then pass to Tcl. Once the handle comes back to your C/C++
> code, you can then convert it back to a pointer using
> GetPointerForObj, which safely reverses the process.
The thing is I want to define a procedure in TCL (not in C/C++) and
then pass this proc to C function. I mean something like that:
<b>proc abc {} { ... }</b> //this procesure is defined within tcl
interpreter
<b>my_c_func $arg1 $arg2 abc</b> //this procedure is defined in TCL C
Api, and it uses abc as a callback
I know that it is possible to check whether the object passed to
function is a procedure name (with obj->typePtr->name). But I still
don't know how to execute it as pure C pointer.
It is also possible to poke your eye with a sharp stick, but don't do
either of those!
The type of a Tcl_Obj is just a cache of the last type that was referred
through a name. But Tcl_Objs are really just strings, the whole
machinery is there to improve performance without changing the semantics.
If you had
proc abc {} { ...}
set abc 1
and now look at the type of the "abc" Tcl_Obj you will NOT see it as a
procName ... but it is a procName, as can be seen from
set x [abc]
If you really want to know if some obj defines a proc's name you'll need
to ask the interp via [info proc] ...
> But I still
> don't know how to execute it as pure C pointer.
Hmmm ... a Tcl proc is not a plain C function, you cannot just execute
the pointer. It has to be fed to the correct Tcl interpreter!
My guess is that what you want is something like
...
/*
* Either use a new Tcl_Obj for the name, or reuse one you got
* from the Tcl interpreter - I am not clear as to how your program
* is organized
*/
Tcl_Obj *cmdPtr[1];
cmdPtr[0] = Tcl_NewStringObj("abc", -1);
Tcl_IncrRefCount(cmdPtr[0]);
/* keep this around for efficiency */
...
result = Tcl_EvalObjv(interp, 1, cmdPtr, 0);
if (result != TCL_OK) {
/* do something */
...
} else {
/* do something else */
...
}
Your example has a proc without arguments. If there are arguments you'll
need to make the cmdPtr array large enough and then populate it and
manage the refCount of the arguments.
Say, are you really _sure_ you want the C code to call back into Tcl ?
In some circumstances it is the way to go, like iterators, or other
polymorphic structure traversal. But in most other cases, returning a
list does marvels...
While we're at it, can you wummarize what your extension does, and the
performance bottleneck that led you to this tight coupling ?
-Alex