如何在 SWIG 中公开 C 字符串数组 char[M][N]?

3

我有一个遗留的C/C++结构体,像这样(还有许多其他成员):

struct S {
  char one_name[MAX_LEN];
  char names[N_NAMES][MAX_LEN];
}

还有一个创建这些的C函数:

S *get_S(...)

我希望通过SWIG导出S和name,以便我可以在python中执行以下操作:
s = MyModule.get_S()
print s.one_name # I have this working
print s.names[1] # should print the 2nd string, this is harder

我想我需要某种类型映射,但我对swig还不熟悉。我可以使用wrapped_array模板来处理one_name,例如SWIG/python array inside structure,但我不确定如何将其扩展为字符串数组。我只需从python中读取这些字符串(如上所述),而不是写入它们。我可以使用访问器来处理它,因此python代码看起来像:

print s.get_name(i) # prints the ith name

然而,我更喜欢使用数组接口,因为它与C语言接口相似。


你没有使用std::string的原因是什么?SWIG可以自动处理它。 - Oliver
@Schollii: 我无法修改我正在封装的底层接口,因为它是古老的 C 代码。如果需要的话,我可以编写一个访问函数,而不是直接暴露字符串数组。我只是希望以一种 Pythonic 的方式来暴露它,并且与现有的 C 代码尽可能相似,这样对用户来说会更加熟悉。 - GaryO
1个回答

1
如果您只需要从Python中读取它们,那么一个快速的解决方案是创建一个适配器类,使用std::string和一个适配器函数。这些都通过%inline放入.i文件中,还需要%rename和可能的%ignore。例如,
%ignore(S)
%rename(S) Swrap
%rename(get_S) get_SWrap
%newobject get_Swrap

%inline %{
struct Swrap
{
     inline Swrap(S* s): one_name(s.one_name) 
     {
          for (i=0; i<N_NAMES; ++i)
               names[i] = s.names[i];
          // no longer need s:
          delete s; 
     }

     string one_name;
     string names[N_NAMES];    
};

Swrap* get_Swrap() {
    return new Swrap(get_S());
}
%}

如果我理解你的解决方案,我认为我没有表达清楚。当我说我只需要读取字符串时,我是指从Python中读取(我的S结构在C端创建和管理)。您的解决方案适用于在C端只读取的字符串。也许有一种类似的想法可以反过来使用,我会再考虑一下。我正在学习Swig有很多钩子可以替换几乎任何东西。 - GaryO
在你的代码中,你创建了一个S,然后修改它的数据成员。除此之外,你需要做更多的事情吗?比如将它传递给一个修改数据成员的导出C++函数?你能否请举例说明你想从Python中执行的操作,这将非常有帮助。 - Oliver
我更新了问题,希望现在更清晰明了。 - GaryO
我更新了我的答案。请注意,%extend非常强大,可能会使这个过程更简单。 - Oliver
@garyo看起来你接受了,但没有点赞;还是不清楚,或者其他原因? - Oliver
在我的实际情况中,我无法简单地复制原始对象,因为底层对象更加动态,但这确实指引了我正确的方向 - 谢谢! - GaryO

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接