Как управлять вложенными структурами в ctypes? - PullRequest
0 голосов
/ 07 апреля 2020

У меня есть библиотека C ++ со следующим объединением:

typedef union DVersion
{
    uint32_t VMask;
    struct
    {
        uint8_t Build;
        uint8_t Rev;
        uint8_t Min;
        uint8_t Maj;
    };
}DATA_VER;

И еще одна структура с полем, которое содержит это

typedef struct DH
{
    uint16_t   Tok1;
    DATA_VER   DVersion;
    uint16_t   DataCount;
}DataHeader

Когда я использую эту DLL на C ++, она отлично работает также на C#. Таким образом, DLL проверена.

Когда я работаю на Python с использованием ctypes, похоже, что количество байтов не соответствует.

Я пробовал эти решения

Решение 1:

class VER_Struct(Structure):
    _fields_ = [("Build", c_uint8),
                ("Rev",  c_uint8),
                ("Min",  c_uint8),
                ("Maj",  c_uint8)]

class DATA_VER(Union):
    _anonymous_ = ("u",)
    _fields_ = [("VMask", c_uint32, 32), 
                ("u",VER_Struct)]

class DataHeader(Structure):
    _fields_ = [("Tok1", c_uint16, 16),
                ("DVersion", DATA_VER),
                ("DataCount", c_uint16, 16)]

Решение 2:

class DATA_VER(Union):
    _fields_ = [("VMask", c_uint32, 32), 
                ("Build", c_uint8),
                ("Rev",  c_uint8),
                ("Min",  c_uint8),
                ("Maj",  c_uint8)]

class DataHeader(Structure):
    _fields_ = [("Tok1", c_uint16, 16),
                ("DVersion", DATA_VER),
                ("DataCount", c_uint16, 16)]

В обоих случаях Tok1 имеет правильное значение, но DVersion и DataCount являются не отображается правильно. Мне кажется, что байты смещены из-за вложенной структуры.

Не могли бы вы намекнуть, что я делаю неправильно? Большое вам спасибо за продвинутый!

1 Ответ

1 голос
/ 07 апреля 2020

Я выяснил это!

Даже если это не указано в документации по ctypes, хорошей практикой является включение _pack_ = 1 в ваши структуры. В моем случае это было:

class VER_Struct(Structure):
    _fields_ = [("Build", c_uint8),
                ("Rev",  c_uint8),
                ("Min",  c_uint8),
                ("Maj",  c_uint8)]

class DATA_VER(Union):
    _anonymous_ = ("u",)
    _fields_ = [("VMask", c_uint32, 32), 
                ("u",VER_Struct)]

class DataHeader(Structure):
    _pack_   = 1
    _fields_ = [("Tok1", c_uint16, 16),
                ("DVersion", DATA_VER),
                ("DataCount", c_uint16, 16)]

Надеюсь, это поможет кому-то еще!

...