【问题标题】:ctypes structure with char array empty in shared library共享库中 char 数组为空的 ctypes 结构
【发布时间】:2019-01-08 10:03:51
【问题描述】:

我有一个共享 C 库,其中包含一个我想在我的 python 代码中使用的结构

struct my_struct {
  char name[64];
};

所以在 python 中我重新创建它

class MyStruct(ctypes.Structure):
  _fields_ = [
    ("name", ctypes.c_char*64)
  ]

当我检查 MyStruct.name 的类型时,我得到 'str',而我期望的是 'c_char_Array_64'。

s=MyStruct()
print type(s.name) # <type 'str'>

所以当我设置“名称”并尝试使用它时,C 将其视为空白。

s.name="Martin"
lib=ctypes.cdll.LoadLibrary('./mylib.so')
lib.my_func(s) # prints ''

其中 lib 是加载了 ctypes 的共享 C 库,而 my_func 只是打印 struct->name

void my_func(struct my_struct *s){
  printf("Hello %s\n", s->name);
}

我想知道为什么ctypes.Structure将char-array转换为字符串以及如何在上面指定的情况下使用它。

谢谢

更新与解决方案

感谢@CristiFati 帮助调试此问题。我已将他的答案标记为正确,因为它实际上是已发布问题的答案。在我的情况下,问题是 Python 和 C 程序中的结构不是 等长。因此,对于将来偶然发现这个问题的人,请非常仔细地检查您的结构实际上是否被平等地定义。

【问题讨论】:

  • 你能说明 my_func 是如何在 C 中定义并包装在 ctypes/python 中的吗?
  • 上面已经显示了
  • 您需要在 Python (lib.my_func.argtypes = [ctypes.POINTER(MyStruct)]) 中为您的函数定义 argtypes(和 restype),然后调用它:lib.my_func(ctypes.pointer(s)))。大多数 ctypes 失败都是由于这个原因。查看stackoverflow.com/questions/53182796/…(以及大量其他问题)了解更多详情。
  • 谢谢@CristiFati,我会试试这个
  • 对不起@CristiFati,s->名字还是空白。还有什么我可以尝试的其他方法吗?

标签: python arrays string ctypes


【解决方案1】:

你做错了什么,但不看完整的代码我不能说什么。所以我准备了一个可行的小例子。
我还发布了[Python 3]: ctypes - A foreign function library for Python 作为参考。

dll.c

#include <stdio.h>
#include <stdlib.h> 

#if defined(_WIN32)
#  define DLL_EXPORT __declspec(dllexport)
#else
#  define DLL_EXPORT
#endif


typedef struct Struct0_ {
    char name[64];
} Struct0;


DLL_EXPORT void test(Struct0 *ps0){
    printf("Hello %s\n", ps0->name);
}

code.py

#!/usr/bin/env python3

import sys
import ctypes


DLL = "./dll.dll"

CharArr64 = ctypes.c_char * 64

class Struct0(ctypes.Structure):
    _fields_ = [
        ("name", CharArr64),
    ]


def main():
    dll_dll = ctypes.CDLL(DLL)
    test_func = dll_dll.test
    test_func.argtypes = [ctypes.POINTER(Struct0)]

    s0 = Struct0()
    s0.name = b"Martin"
    res = test_func(ctypes.pointer(s0))


if __name__ == "__main__":
    print("Python {:s} on {:s}\n".format(sys.version, sys.platform))
    main()

输出

(py_064_03.06.08_test0) e:\Work\Dev\StackOverflow\q054089371>"c:\Install\x86\Microsoft\Visual Studio Community\2015\vc\vcvarsall.bat" x64

(py_064_03.06.08_test0) e:\Work\Dev\StackOverflow\q054089371>dir /b
code.py
dll.c

(py_064_03.06.08_test0) e:\Work\Dev\StackOverflow\q054089371>cl /nologo /DDLL /MD dll.c  /link /NOLOGO /DLL /OUT:dll.dll
dll.c
   Creating library dll.lib and object dll.exp

(py_064_03.06.08_test0) e:\Work\Dev\StackOverflow\q054089371>dir /b
code.py
dll.c
dll.dll
dll.exp
dll.lib
dll.obj

(py_064_03.06.08_test0) e:\Work\Dev\StackOverflow\q054089371>"e:\Work\Dev\VEnvs\py_064_03.06.08_test0\Scripts\python.exe" code.py
Python 3.6.8 (tags/v3.6.8:3c6b436a57, Dec 24 2018, 00:16:47) [MSC v.1916 64 bit (AMD64)] on win32

Hello Martin

(py_064_03.06.08_test0) e:\Work\Dev\StackOverflow\q054089371>rem Also run with Python 2.7 ... Not recommended.

(py_064_03.06.08_test0) e:\Work\Dev\StackOverflow\q054089371>"e:\Work\Dev\VEnvs\py_064_02.07.15_test0\Scripts\python.exe" code.py
Python 2.7.15 (v2.7.15:ca079a3ea3, Apr 30 2018, 16:30:26) [MSC v.1500 64 bit (AMD64)] on win32

Hello Martin

【讨论】:

  • 我最好的猜测是 OP 没有为函数设置参数类型,因此结构是按值而不是指针传递的。也就是说,该函数将字符串'Martin\0\0' 解释为指向MyStruct 的指针。例如。比较 libc.printf(b'hello %sn', s)libc.printf(b'hello %s\n', ctypes.byref(s))。前者打印垃圾,而后者则将指向s 的指针作为第二个参数传递(恰好与指向s-&gt;name 的指针相同)。
  • @Dunes:我在一条评论中指定了如何调用该函数,根据下一条评论,这已经完成了。然后我很想看看能不能复现,我把答案贴出来了。
  • @CristiFati 我已经尝试过您的代码,它运行良好。甚至尝试将其移植回我的代码的样子,它仍然可以工作。我没有发布“整个代码”,因为它是一个我正在构建的大型项目,我认为我发布的内容足以找到问题。但事实并非如此。代码中一定有其他地方会干扰“通过引用传递”的工作方式?感谢您的帮助
  • stackoverflow.com/questions/373419/…。在这种情况下,它与如何从 Python 调用函数有关。在代码中有两个地方:ctypes.POINTERctypes.pointer,它们是关键,你可能错过了其中一个。也可能是您做了更改(在 C 源中),但忘记重建。
  • 已解决。 @克里斯蒂法蒂。我发现并发布了,正如你所说的“没有看到整个代码......”。事实证明,python 和 C 中的结构长度不相等,这导致数据的实际位置不匹配。我仍然会接受您的回答,因为它实际上是对所述问题的回答。感谢您的帮助。
猜你喜欢
  • 1970-01-01
  • 2021-04-25
  • 1970-01-01
  • 2019-02-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-07-02
  • 2013-01-11
相关资源
最近更新 更多