【问题标题】:Accessing data from a structure returned by C function in Python using ctypes使用 ctypes 从 Python 中 C 函数返回的结构中访问数据
【发布时间】:2017-08-25 14:13:54
【问题描述】:

我知道该主题已经过治疗,但我没有找到任何适合我的方法,所以我想我的问题与其他问题略有不同。

我所做的基本上是使用 ctypes 将 C 函数包装到 python 代码中。 我的目标是在 C 函数中计算一些量,将它们存储到单个结构中,然后在 Python 中返回结构,我可以在其中读取结构中的所有不同数据。

所以:

为了在 python 中定义我的结构,我使用:

class BITE(ctypes.Structure):
    _fields_ = [
                ("lum", ctypes.c_int),
                ("suce", ctypes.c_int)
                ]

我是这样编译的:

sub.call(["gcc","-shared","-Wl,-install_name,ex.so","-o","ex.so","-fPIC","ex.c"])


lum = ctypes.CDLL('ex.so')
lum = lum.lum

我这样声明参数和结果类型:

lum.restype = ctypes.POINTER(BITE)
lum.argtypes = [ctypes.POINTER(ctypes.c_float),ctypes.c_int,ctypes.POINTER(ctypes.c_float),ctypes.c_int,ctypes.POINTER(ctypes.c_float),ctypes.POINTER(ctypes.c_float),ctypes.c_int,ctypes.POINTER(ctypes.c_float),ctypes.c_int,ctypes.POINTER(ctypes.c_float),ctypes.POINTER(ctypes.c_float),ctypes.POINTER(ctypes.c_float),ctypes.POINTER(ctypes.c_float),ctypes.c_float,ctypes.c_float,ctypes.c_float,ctypes.c_float,ctypes.c_float]

然后,我在python代码中调用C函数“lum”

out = lum(all the different variables needed)

问题从这里开始。我有我的结构,但无法读取存储在每个字段中的数据。

我找到的部分解决方案是:

out = out[0]

但是,在做的时候

print(out.suce)

我有一个分段错误 11。不知道为什么。我试图了解如何使用 create_string_buffer,但我并不真正了解它是如何工作的以及它应该做什么。此外,我尝试将其用作黑匣子,但仍然没有任何效果。

我还尝试了其他线程中提到的其他解决方案,例如使用 out.contents 或类似的东西,但它没有 .contents 属性。也不是 out.suce.value,这也是我在绝望的研究中看到的东西。

当然,我在 C 代码中检查了结构存在,结构的每个字段都存在,并且其中包含正确的数据。

谢谢。

【问题讨论】:

  • 提供minimal reproducible example。如果我们无法重现问题或至少无法查看实际代码,则无法确定您做错了什么。

标签: c python-3.x ctypes


【解决方案1】:

假设你有一个像这样的 C 结构:

typedef struct _servParams
{
   unsigned short m_uServPort;
   char m_pInetAddr[MAX_LENGTH_OF_IP_ADDRESS];
} ServerParams_t;

要在 ctypes 中使用它,您应该像这样创建一个包装器:

class ServerParams_t(Structure):
        _fields_ = [    ("m_uServPort", c_ushort),
                        ("m_pInetAddr", (c_char * 16)) ]

稍后在您的 python 中,您可以使用以下 sn-p :

servParams = ServerParams_t()
servParams.m_uServPort = c_ushort(int(port))
servParams.m_pInetAddr = ip.encode()

如果您需要按值传递,只需将 servParams 变量传递给您的 api。如果您需要传递指针,请使用byref(servParams)

【讨论】:

  • 谢谢,但我不太明白它是如何工作的;在我看来 servParams = Serverparams_t() 将删除存储在结构中的值。对于其他行,我不明白什么是端口或 ip;encode()。
  • 第一行 - 结构实例被创建。在定义此结构的实例时,类似于您在 C 代码中的内容。第 2 行 - 将由名为“port”的局部变量定义的值分配给 m_uServPort 成员 第 3 行 - 将字符串值分配给“m_pInetAddr”字段。假设您将“192.168.0.1”存储在“ip”变量中,并且您想将其分配给“m_pInetAddr”字段 - 那么这就是我在这里写的。
  • 好的,谢谢,但是这样做,我会丢失以前存储在我的结构中的值。我不想在我的结构中重新分配新值。我在我的 C 代码中创建结构。我在我的 C 代码中计算不同的值,并在我的 python 代码中返回带有这些值的结构,我希望在其中访问这些值,在 C 代码中计算。如果我正确理解您所说的话,我会为结构的每个字段重新分配新值。所以我放弃了我的 C 代码的计算结果。
  • 你的API原型是什么?
  • 我不知道。
猜你喜欢
  • 2022-01-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-01-30
  • 1970-01-01
相关资源
最近更新 更多