首页 > 解决方案 > 在 ctypes 中部分定义 Struct 定义

问题描述

我不精通 Python-C 接口,我正在使用 C SDK。

调用了这个结构,NET_ITS_PLATE_RESULT我只需要从 API 回调函数中检索。dwSizebyPicNo

在我的回调函数(Python)中,我将使用该memmove函数来复制结果内存块。只定义一个部分struct并且仍然能够获得我想要的实际结果是一个好习惯吗?就像我在下面定义的那样

class NET_ITS_PLATE_RESULT(ctypes.Structure):

    _fields_ = [
        ("dwSize", ctypes.c_uint),
        ("byPicNo", ctypes.c_byte)
    ]

来自文档:NET_ITS_PLATE_RESULT(实际定义要长得多)

struct{
  DWORD                    dwSize;
  DWORD                    dwMatchNo;
  BYTE                     byGroupNum;
  BYTE                     byPicNo;
  BYTE                     bySecondCam;
  BYTE                     byFeaturePicNo;
  BYTE                     byDriveChan;
  BYTE                     byVehicleType;
  BYTE                     byDetSceneID;
  BYTE                     byVehicleAttribute;
}NET_ITS_PLATE_RESULT, *LPNET_ITS_PLATE_RESULT;

标签: pythonctypes

解决方案


为简单起见,在提及结构大小时,我将忽略(默认为 4 字节)内存对齐,并表现得像它们将是一个字节对齐一样,因此结构的大小等于其成员大小的总和。

例子:

>>> import ctypes
>>>
>>> class Struct0(ctypes.Structure):  # Your NET_ITS_PLATE_RESULT structure, with a shorter name
...     _fields_ = [
...         ("dwSize", ctypes.c_uint),
...         ("byPicNo", ctypes.c_byte)
...     ]
...
>>>
>>>
>>> class Struct0Pack001(ctypes.Structure):
...     _pack_ = 1
...     _fields_ = [
...         ("dwSize", ctypes.c_uint),
...         ("byPicNo", ctypes.c_byte)
...     ]
...
>>>
>>> print(ctypes.sizeof(Struct0))
8
>>> print(ctypes.sizeof(Struct0Pack001))
5

当您的回调函数的调用者(来自您的其他问题的SDK)将调用它时,它将尝试填充其NET_ITS_PLATE_RESULT参数(如果参数是指针(很可能),则填充到参数指向的内存,或者直接在如果不是,则堆栈),因此要写入sizeof(NET_ITS_PLATE_RESULT)16)个字节-因为它期望该结构。

但是您只会传递5个字节,因此SDK将尝试在其“允许的”内存区域之外写入,从而导致未定义的行为。您可能会得到segfault访问冲突)。

此外,考虑到程序将通过上述阶段,因为您消除了一些字段(dwMatchNobyGroupNum),您将不会在byPicNo中获得正确的数据,而是dwMatchNo的第一个字节

所以,永远不要选择这样的捷径,除非你真的知道你在做什么以及处理它们的代码在做什么——这似乎不是这里的情况。

嗯,看着dwSize成员,我正在考虑MS结构(例如[MS.Docs]: OSVERSIONINFOEXW 结构),其第一个成员是它们的大小,并且在将结构(指针)传递给API之前需要相应地设置它正在填充其(相关)成员。检查这种情况也会很有趣。但无论如何,它不可能与提议的NET_ITS_PLATE_RESULT 一起使用


推荐阅读