swig-php 包装器使用指针,c 代码是一个数组

Posted

技术标签:

【中文标题】swig-php 包装器使用指针,c 代码是一个数组【英文标题】:swig-php wrapper uses pointer, c code is an array 【发布时间】:2010-12-21 22:55:09 【问题描述】:

我正在使用 SWIG 生成一个调用“c”共享库的 php 扩展。除了以下情况外,我能够完成大多数工作......

在我的“c”代码中,我将函数声明为(请注意结构和函数名称已更改以保护无辜者):

int getAllThePortInfo(EthernetPort *ports);

在这种情况下,参数ports实际上是一个EthernetPort结构数组。在另一个“c”程序中,我可以这样称呼它......

EthernetPort ports[4];
int rval = getAllThePortInfo(ports);
<etc>
<etc>

这很好用。然后我运行 SWIG,生成我的共享库,并且所有构建都很好。我得到了可以调用的 php 代码...

$ports = new_ethernetport();
$rval = getAllThePortInfo($ports);

这会导致 PHP 抛出以下错误:php: free(): invalid pointer: 0x099cb610

所以,我尝试做类似...

$ports = array(new_ethernetport(), new_ethernetport(), new_ethernetport(), new_ethernetport());
$rval = getAllThePortInfo($ports);

但后来 PHP 抱怨... PHP 致命错误:在 getAllThePortInfo 的参数 1 中键入错误。预期 SWIGTYPE_p_EthernetPort

我认为发生的事情是 PHP(和 SWIG)不区分指针和数组,并且在包装器中,它正在考虑“指向单个结构的指针”,而实际上,它是一个结构数组.

PHP 中有什么我可以做的吗?分配一块我可以用作存储多个结构的空间的内存?

我可以通过 SWIG 做些什么来让我的包装器更好地理解我的意图吗?

我真的很感激任何建议。谢谢。

【问题讨论】:

在你的C代码中,调用者如何知道getAllThePortInfo()需要的数组的大小?是否固定为 4? 如果您改为声明int getAllThePortInfo(EthernetPort ports[]); 会怎样?我知道 C 编译器无论如何都会将其更改为指针,但它可能会对 SWIG 产生影响? 也许您可以发布 interface.i 文件的一些相关部分。 回答您的问题... [@caf] 是的,大小是固定的。 [@netcoder] 我尝试了这种改变。它仍然是 SWIG 中的指针。在文档中,SWIG 声明它将所有数组都视为指针以方便操作。 [@mario] 我的 .i 文件没有什么特别之处。我只包含我的 .h 文件,该文件声明了函数并在其中包含一些结构和#defines。 昨晚我在阅读有关 SWIG 的 carrays.i 模块的信息。任何关于使用它来解决我的问题的cmets?我还没有让它工作,但会继续努力。 【参考方案1】:

carrays.i 确实回答了我的问题...

在 SWIG 接口文件中,我有以下几行...

%include <carrays.i>
%array_functions(EthernetPort, ethernetPortArray);
%include "my_lib.h"

"my_lib.h" 包含 EthernetPort 结构的 typedef,以及函数声明...

#define NUM_ETHERNET_PORTS 4

typedef struct 
    int number;
    mode_t mode;
 EthernetPort;

int getAllThePortInfo(EthernetPort *ports);

运行 SWIG 并构建共享库 my_lib.so 后,我可以使用以下 PHP 代码...

$ports = new_ethernetPortArray(NUM_ETHERNET_PORTS);
$rval = getAllThePortInfo($ports);

$port0 = ethernetPortArray_getitem($ports, 0);
$pnum = ethernetport_number_get($port1);
$pmode = ethernetport_mode_get($port1);

// port1 port2 port3 etc etc 

delete_ethernetPortArray($ports);

php 函数 new_ethernetPortArrayethernetPortArray_getitemethernetport_number_getethernetport_mode_getdelete_ethernetPortArray都是 SWIG 基于 .i 文件创建的。

SWIG 带来的另一个好处是在我的 php 代码中使用#define(例如 NUM_ETHERNET_PORTS),让我可以在一个地方存放一些常用数据。我喜欢。 :-)

干杯。

【讨论】:

【参考方案2】:

@DoranKatt,您的解决方案也对我有用,只需稍作调整。我不得不更改 swig 文件中的顺序:

%include <carrays.i>
%include "my_lib.h"
%array_functions(EthernetPort, ethernetPortArray);

按照原始顺序,我发现它生成的代码无法编译,因为数组函数引用了稍后包含在“my_lib.h”中的类型。当然,我的代码使用了不同的名称和类型,但为了清楚起见,我保留了原始作者的姓名。

感谢您发布原始问题和答案。这把我从一个洞里挖了出来。我在 swig 文档中找不到任何关于此的内容。

【讨论】:

以上是关于swig-php 包装器使用指针,c 代码是一个数组的主要内容,如果未能解决你的问题,请参考以下文章

C++ 智能指针和指针到指针输出 API。模板化的“包装器”

如何将 OpenCV 的 MatExpr 的 C 包装器的指针输出转换回 MatExpr

C++11——— 包装器

C++11——— 包装器

从 .NET 代码中销毁非托管对象

SWIG C++ Python:通过引用或指针包装 int