我一直在使用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 *
)返回,因为每当我尝试上述方法时,它们似乎总是会返回一些垃圾数据与数组有关,因为我甚至不知道从哪里开始工作。我很确定两者背后的过程是相似的,因为一个是一个字符数组,另一个只是一个数组...好吧,别的。
任何帮助解决这个问题都将非常感激。我已经做了好几天了,在搜索任何涉及ffidl的非常好的例子时,我的Google-fu失败了。
编辑:自我发帖以来,我使用::ffidl::pointer-into-string
命令管理了一些难以让字符串工作的问题。这基本上只是查看内存并复制字节,直到它达到零点(我猜)。这不是我觉得最佳方法应该是什么,因为这似乎不适用于引用,因为我不能通过引用传递指针到内存中的特定位置,只是期望它工作没有后果。 (如果我不清楚,基本上我要做的就是相当于在我当前的内存块中选择一个随机子地址并说“嗯,是的。这似乎是放置一些数据的好地方。”这确实是一个坏主意。)
我将继续努力,试图弄清楚如何让数组工作。从复制内存开始并尝试使用一些binary scan
s。
答案 0 :(得分:1)
Tcl 真的喜欢能够管理其值本身的生命周期,并且它使用不可变值模型。 (现实情况比较复杂,但是对模型进行编程,请!)即使值不会改变,你仍然需要复制,除非你能告诉数据生成器使用Tcl自己的内存分配器, Tcl_Alloc
,但在您愿意复制的情况下可以使用多种快捷方式(例如,请参阅Tcl_SetResult
)。
这意味着通过引用传入的对象确实应该映射到一个抽象对象(其表示形式是一个任意名称,例如handle-12345
)并且在其上有许多操作,它们返回有关手柄代表的对象;对于您的情况,一个这样的操作将返回子字符串的副本,另一个可能是返回总长度。唯一的强制操作是处理句柄的显式处理。
我知道这听起来非常笨重。这只是实际阻抗不匹配的自然结果。
答案 1 :(得分:0)
经过大量的工作,我终于得出了以下[相对反高潮]的结论。我认为,如果我要记录我的解决方案,那么寻找这个答案的其他人(如果有的话)会受到赞赏。无论如何,从一开始,使用一些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
}
可能有一个更好的方法来做到这一点,但这肯定有效,我很高兴。但是,如果有人有更好的方式,我仍然愿意接受这些想法。