将 Ffidl 与 TCL 结合使用返回引用传递字符串和数组

发布于 2024-10-31 08:21:49 字数 1057 浏览 2 评论 0原文

我一直在使用 Ffidl 来处理一些使用 FTDI 驱动程序的设备,并且在大多数情况下它都运行得相当好。我相当确定我失败的地方是因为我对 TCL 如何在幕后处理指针缺乏了解。无论如何,我已经通过执行以下操作获得了有关通过引用传递工作的函数的示例:

::ffidl::callout rpbrd {pointer-var} int \
        [ffidl::symbol [ffidl::find-lib library] returns_pass_by_reference_double]
set dbl_ptr = [binary format [::ffidl::info format double] 1]
set my_int = [rpbrd dbl_ptr]
binary scan $dbl_ptr [::ffidl::info format double] my_dbl
puts $my_dbl

但是,我尚未弄清楚的两件事是返回“按引用”字符串 (char *< /code>),因为每当我尝试上述方法时,它们似乎总是返回一些垃圾数据,以及与数组有关的任何数据,因为我什至不知道从哪里开始让它们工作。我很确定这两者背后的过程是相似的,因为一个是字符数组,另一个只是......好吧,其他东西的数组。

任何帮助解决这个问题的帮助将不胜感激。我已经研究了好几天了,当我搜索任何涉及 ffidl 的真正好的例子时,我的 Google-fu 失败了。

编辑:自从我发帖以来,我已经设法使用 ::ffidl::pointer-into-string 命令让字符串正常工作,但遇到了一些困难。它基本上只是查看内存并复制字节,直到它达到零点(我猜)。这不是我认为最佳方法应该是的,因为这似乎不适用于引用,因为我无法通过引用传递指针到内存中的特定位置,并且只是期望它能够正常工作而不会产生任何后果。 (如果我不清楚的话,基本上我要做的就是在当前的内存块中选择一个随机子地址,然后说“嗯,是的。这似乎是放置一些数据的好地方。”这确实是一个坏主意。)

我将继续努力尝试找出如何让数组工作。从复制内存开始,并尝试使用一些二进制扫描来对字节进行魔法处理。

I've been using Ffidl to work with some devices that use the FTDI drivers, and for the most part it's all working fairly well. I'm fairly certain that the area that I'm failing in comes from my lack of understanding of how TCL handles pointers behind the scenes. In any case, I've gotten examples regarding functions that pass by reference to work by doing something like this:

::ffidl::callout rpbrd {pointer-var} int \
        [ffidl::symbol [ffidl::find-lib library] returns_pass_by_reference_double]
set dbl_ptr = [binary format [::ffidl::info format double] 1]
set my_int = [rpbrd dbl_ptr]
binary scan $dbl_ptr [::ffidl::info format double] my_dbl
puts $my_dbl

However, two things that I have not yet managed to figure out are return "by reference" strings (char *), because they always seem to return some junk data, whenever I try the above approach, as well as anything to do with arrays, because I don't even know where to begin to get those to work. I'm pretty sure that the process behind the two would be similar, since one is an array of characters, and the other would just be an array of... well, something else.

Any help figuring this out would be much appreciated. I've been working on it for days, and my Google-fu is failing when searching for any really good examples involving ffidl.

Edit: since the time of my post, I've managed, with some difficulty to get strings to work, using the ::ffidl::pointer-into-string command. Which basically just looks at the memory and copies bytes until it reaches a null point (I'm guessing). This is not what I feel the optimum method should be, because this doesn't seem to work for by reference, since I can't pass the pointer by reference to a specific location in memory and just expect it to work without consequence. (If I'm not being clear, basically what I'd be doing is the equivalent of picking a random subaddress in my current block of memory and saying "Hmm, yep. That seems like a good spot to just put some data." which is indeed a bad idea.)

I'm going to keep chugging along to attempt to figure out how to get arrays to work. Starting with copying memory over and trying to work magic the bytes with some binary scans.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

浪漫之都 2024-11-07 08:21:49

Tcl确实希望能够管理其值本身的生命周期,并且它使用不可变的值模型。 (现实更复杂,但是请对模型进行编程!)即使值不会改变,您仍然需要复制,除非您可以告诉数据生成器使用 Tcl 自己的内存分配器, Tcl_Alloc,尽管在​​您愿意复制的情况下有许多可用的快捷方式(例如,请参阅Tcl_SetResult)。

这意味着通过引用传入的对象实际上应该映射到一个抽象对象(其表示形式是任意名称,例如handle-12345),并且该对象具有许多返回信息的操作关于句柄所代表的对象;对于您的情况,这样的操作之一是返回子字符串的副本,另一个操作可能是返回总长度。唯一的强制操作是处理句柄的显式处置。

我知道这听起来很笨拙。这只是实际阻抗不匹配的自然结果。

Tcl really likes to be able to manage the lifetime of its values itself, and it uses an immutable value model. (The reality is more complex, but program to the model, please!) Even if the value wasn't going to change, you'd still need to copy unless you could tell the generator of the data to use Tcl's own memory allocator, Tcl_Alloc, though there are a number of shortcuts available in the case where you are happy to copy (see Tcl_SetResult for example).

This means that the object passed in by reference really should be mapped to an abstract object (whose representation is an arbitrary name, such as handle-12345) and which has a number of operations on it which return information about the object represented by the handle; one such operation for your case would be to return a copy of a substring, another might be to return the overall length. The only mandatory operation is handling an explicit disposal of the handle.

I know this sounds all very clunky. It's just a natural consequence of a real impedance mismatch.

£烟消云散 2024-11-07 08:21:49

经过一番努力,我终于得出了下面这个【比较虎头蛇尾】的结论。我认为如果我记录我的解决方案,其他寻找这个答案的人(如果有的话)将不胜感激。无论如何,从一开始,使用一些 C 代码,考虑函数

void make_int_array(int*& out) {
    int* a = new int[5];
    for (int i = 0; i < 5; i++) {
        a[i] = i+1;
    }
    out = a;
}

本质上,这一切所做的就是创建一个新的 {1,2,3,4,5} 数组并将其用作 out 指针。接下来,我们将编写 Tcl 包装器:

::ffidl::callout _make_int_array {pointer-var} void \
                  [::ffidl::symbol ffidltest.dll make_int_array]

之后,您需要“烹饪”一些接口来使用 make_int_array 函数。你可以这样做:

proc make_int_array {} {
    set ints 5
    set intsize [::ffidl::info sizeof int]
    set bytesize [expr $intsize * $ints]

    set ptr [binary format [::ffidl::info format int] 1]
    _make_int_arrayptr ptr
    binary scan $ptr i ptr

    binary scan [::ffidl::peek $ptr $bytesize] \
                [::ffidl::info format int]$ints out
    return $out
}

可能有更好的方法来做到这一点,但这绝对有效,我对此感到高兴。然而,如果有人有更好的方法,我仍然愿意接受想法。

After a lot of work, I finally came to the following [relatively anti-climactic] conclusion. I figured that it would be appreciated for other people looking for this answer (if there ever is anyone) if I were to document my solution. Anyways, from the beginning, with some C code, consider the function

void make_int_array(int*& out) {
    int* a = new int[5];
    for (int i = 0; i < 5; i++) {
        a[i] = i+1;
    }
    out = a;
}

Essentially all this does is create a new array of {1,2,3,4,5} and use that for the out pointer. Next, we'll write the Tcl wrapper:

::ffidl::callout _make_int_array {pointer-var} void \
                  [::ffidl::symbol ffidltest.dll make_int_array]

After that, you'll need to "cook" a few interfaces to use the make_int_array function. You can do that like so:

proc make_int_array {} {
    set ints 5
    set intsize [::ffidl::info sizeof int]
    set bytesize [expr $intsize * $ints]

    set ptr [binary format [::ffidl::info format int] 1]
    _make_int_arrayptr ptr
    binary scan $ptr i ptr

    binary scan [::ffidl::peek $ptr $bytesize] \
                [::ffidl::info format int]$ints out
    return $out
}

There may be a much nicer way to do this, but this definitely worked and I'm happy for that. However, if anyone has a nicer way, I'm still open to ideas.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文