英文:
Using a C library with Python
问题
我正在编写一个在Linux下与以前格式编写的文件进行交互的Python程序('squishDB'格式,其中存储了来自旧的Fidonet网络的消息,时间跨度从1980年到2000年)。
为了与这些文件进行交互,我迄今为止已经使用了C和C++中的程序,它们使用libsmapi.so库,对于这些语言,该库工作得非常好。
现在,作为一个完全用Python编写的更大项目的一部分,我发现自己被迫使用相同的库来帮助我使用cstruct和ctypes,这是我以前从未使用过的。
我尝试编写这个简单的程序,它打开库并获取一个指针,然后可以调用各个函数。
import ctypes
import cstruct
class minf(cstruct.MemCStruct):
__def__ = """
struct _minf
{
short req_version;
short def_zone;
short haveshare; /* filled in by msgapi routines - no need to set this */
/* Version 2 Information */
short smapi_version;
short smapi_subversion;
};
"""
def main():
smapi = ctypes.CDLL('libsmapi.so')
m = minf()
m.def_zone = 2
m.req_version = 0
if smapi.MsgOpenApi(m):
print("Error opening library")
exit(1)
if __name__ == '__main__':
main()
问题是,尽管我使用cstruct从C文件中逐字复制定义了minf()结构,但在将其传递给库调用时出现了这个奇怪的错误。
Traceback (most recent call last):
File "/home/neo/progetti/PycharmProjects/smapitest/main.py", line 33, in <module>
main()
File "/home/neo/progetti/PycharmProjects/smapitest/main.py", line 27, in main
if smapi.MsgOpenApi(m):
^^^^^^^^^^^^^^^^^^^
ctypes.ArgumentError: argument 1: KeyError: '_as_parameter_'
Process finished with exit code 1
有人能帮我吗?
谢谢。
祝好。
英文:
I'm writing a Python program under linux to interact with files written in an old format (the 'squishDB' format, where messages from the old Fidonet network were stored in the years from 1980 to 2000).
To interact with these files, I have so far used programs in C and in C++ they use the libsmapi.so library and with these languages the library works very well.
Now, as part of a larger project all written in Python, I find myself forced to use the same library helping me with cstruct and ctypes, which I had never used before.
I tried to write this simple program, which opens the library and gets a pointer, to then be able to call the individual functions.
import ctypes
import cstruct
class minf(cstruct.MemCStruct):
__def__ = """
struct _minf
{
short req_version;
short def_zone;
short haveshare; /* filled in by msgapi routines - no need to set this */
/* Version 2 Information */
short smapi_version;
short smapi_subversion;
};
"""
def main():
smapi = ctypes.CDLL('libsmapi.so')
m = minf()
m.def_zone = 2
m.req_version = 0
if smapi.MsgOpenApi(m):
print("Error opening library")
exit(1)
if __name__ == '__main__':
main()
The problem is that, despite having defined the minf() structure with cstruct by copying it verbatim from the C file, this strange error appears when I pass it to the library call.
Traceback (most recent call last):
File "/home/neo/progetti/PycharmProjects/smapitest/main.py", line 33, in <module>
main()
File "/home/neo/progetti/PycharmProjects/smapitest/main.py", line 27, in main
if smapi.MsgOpenApi(m):
^^^^^^^^^^^^^^^^^^^
ctypes.ArgumentError: argument 1: KeyError: '_as_parameter_'
Process finished with exit code 1
Anyone can help me?
Thanks.
Regards
答案1
得分: 1
cstruct
与 ctypes
不兼容。请改用 ctypes.Structure
代替:
import ctypes as ct
class minf(ct.Structure):
_fields_ = (('req_version', ct.c_short),
('def_zone', ct.c_short),
('haveshare', ct.c_short),
('smapi_version', ct.c_short),
('smapi_subversion', ct.c_short))
# 提供了一个类来显示自己的方法(可选)
def __repr__(self):
return (f'minf(req_version={self.req_version}, '
f'def_zone={self.def_zone}, '
f'haveshare={self.haveshare}, '
f'smapi_version={self.smapi_version}, '
f'smapi_subversion={self.smapi_subversion})')
smapi = ct.CDLL('libsmapi.so')
# 建议定义参数类型和返回类型。
# 不要假设 ctypes 知道如何转换参数。
# 定义这些允许 ctypes 检查传递的参数类型是否兼容。
#
# 这假定一个 C 原型为 "int MsgOpenApi(struct minf*)"
smapi.MsgOpenApi.argtypes = ct.POINTER(minf),
smapi.MsgOpenApi.restype = ct.c_int
# 替代的初始化方式。
# minf() 将所有参数初始化为零。
# 提供的参数按与 _fields_ 相同的顺序分配。
m = minf(0, 2)
print(m) # 如果未定义 m.__str__,则调用 m.__repr__()。
# 输出:
# minf(req_version=0, def_zone=2, haveshare=0, smapi_version=0, smapi_subversion=0)
if smapi.MsgOpenApi(ct.byref(m)): # 通过引用传递
print("Error opening library")
英文:
cstruct
isn't compatible with ctypes
. Use ctypes.Structure
instead:
import ctypes as ct
class minf(ct.Structure):
_fields_ = (('req_version', ct.c_short),
('def_zone', ct.c_short),
('haveshare', ct.c_short),
('smapi_version', ct.c_short),
('smapi_subversion', ct.c_short))
# Provides a way for a class to display itself (optional)
def __repr__(self):
return (f'minf(req_version={self.req_version}, '
f'def_zone={self.def_zone}, '
f'haveshare={self.haveshare}, '
f'smapi_version={self.smapi_version}, '
f'smapi_subversion={self.smapi_subversion})')
smapi = ct.CDLL('libsmapi.so')
# Recommend defining argument types and return type.
# Don't assume ctypes knows how to marshal your parameters.
# Defining this allows ctypes to check the types of parameters passed are compatible.
#
# This assumes a C prototype of "int MsgOpenApi(struct minf*)"
smapi.MsgOpenApi.argtypes = ct.POINTER(minf),
smapi.MsgOpenApi.restype = ct.c_int
# Alternative way to initialize.
# minf() would initialize all parameters to zero.
# Provided parameters are assigned in the same order as _fields_.
m = minf(0, 2)
print(m) # Calls m.__repr__() if m.__str__ isn't defined.
# Output:
# minf(req_version=0, def_zone=2, haveshare=0, smapi_version=0, smapi_subversion=0)
if smapi.MsgOpenApi(ct.byref(m)): # Pass by reference
print("Error opening library")
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论