Pointers 使用Ffidl和TCL返回按引用传递的字符串和数组

Pointers 使用Ffidl和TCL返回按引用传递的字符串和数组,pointers,dll,tcl,Pointers,Dll,Tcl,我一直在使用Ffidl来处理一些使用FTDI驱动程序的设备,在大多数情况下,它都工作得相当好。我相当肯定,我失败的地方在于我不了解TCL如何在幕后处理指针。在任何情况下,我都得到了一些关于函数的例子,这些函数通过如下操作通过引用传递到work: ::ffidl::callout rpbrd {pointer-var} int \ [ffidl::symbol [ffidl::find-lib library] returns_pass_by_reference_double] s

我一直在使用Ffidl来处理一些使用FTDI驱动程序的设备,在大多数情况下,它都工作得相当好。我相当肯定,我失败的地方在于我不了解TCL如何在幕后处理指针。在任何情况下,我都得到了一些关于函数的例子,这些函数通过如下操作通过引用传递到work:

::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*
),因为每当我尝试上述方法时,它们似乎总是返回一些垃圾数据,以及与数组有关的任何内容,因为我甚至不知道从哪里开始让它们工作。我很确定这两个过程是相似的,因为一个是字符数组,另一个只是。。。嗯,还有别的事

如果你能帮我解决这个问题,我将不胜感激。我已经做了几天了,我的Google fu在搜索任何涉及ffidl的好例子时失败了

编辑:自我发表文章以来,我一直使用
::ffidl::pointer-into-string
命令管理字符串,但有些困难。它基本上只是查看内存并复制字节,直到它达到一个空点(我猜)。这不是我认为最佳的方法应该是什么,因为这似乎不适用于引用,因为我不能通过引用将指针传递到内存中的特定位置,而只是希望它可以正常工作。(如果我不清楚,我所做的基本上相当于在我当前的内存块中选择一个随机子地址,然后说“嗯,是的,这似乎是一个放置一些数据的好地方。”这确实是个坏主意。)

我将继续努力,试图找出如何让阵列工作。从复制内存开始,并尝试通过一些二进制扫描对字节施展魔法。

Tcl非常喜欢能够管理其值本身的生命周期,并且它使用一个不变的值模型。(实际情况更复杂,但请按模型编程!)即使值不会改变,您仍然需要复制,除非您可以告诉数据生成器使用Tcl自己的内存分配器,
Tcl\u Alloc
,尽管在您乐意复制的情况下有许多快捷方式可用(例如,请参见
Tcl_SetResult

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

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

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

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


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

经过大量的工作,我终于得出了以下[相对反高潮]的结论。我想,如果有人在寻找这个答案,我会很感激的如果我要记录我的解决方案,无论如何,从一开始,用一些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;
}
之后,您需要“烹饪”几个接口来使用make_int_数组函数。您可以这样做:

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
}

也许有更好的方法可以做到这一点,但这确实奏效了,我为此感到高兴。然而,如果有人有更好的方法,我仍然愿意接受想法。

经过大量的工作,我最终得出了以下[相对反高潮]的结论。我想,如果其他人能找到这个答案,我将不胜感激(如果有任何人),如果我要记录我的解决方案。无论如何,从一开始,用一些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;
}
之后,您需要“烹饪”几个接口来使用make_int_数组函数。您可以这样做:

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
}

也许有更好的方法可以做到这一点,但这确实奏效了,我为此感到高兴。不过,如果有人有更好的方法,我仍然愿意接受想法。

虽然这有助于我了解Tcl是如何“在幕后”工作的我还不确定如何使用它将Ffidl指向内存位置的指针解释为一个整数数组。不是说这不能回答这个问题,只是我还不知道如何应用它。我不知道我的实现是否真的使用了您特别提到的内容,但我确实认为这很有帮助在某种程度上,我制定了我的解决方案。为此,我感谢你们。虽然这有助于我理解Tcl在“背后”是如何工作的