Реализация перечисления C и объединения в Python - PullRequest
4 голосов
/ 28 сентября 2010

Я пытаюсь выяснить некоторый C-код, чтобы я мог перенести его в python. Код предназначен для чтения проприетарного двоичного формата файла данных. До сих пор это было просто - в основном это структуры, и я использовал библиотеку struct для запроса определенных типов ctypes из файла. Тем не менее, я только что придумал этот фрагмент кода, и я не знаю, как реализовать его в python. В частности, я не уверен, что делать с enum или union.

#define BYTE char 
#define UBYTE unsigned char 
#define WORD short 
#define UWORD unsigned short

typedef enum {
    TEEG_EVENT_TAB1=1, 
    TEEG_EVENT_TAB2=2
} TEEG_TYPE;

typedef struct
{
        TEEG_TYPE Teeg;
        long Size;
    union

        {
            void *Ptr;  // Memory pointer
            long Offset
        };
} TEEG;

Во-вторых, в приведенном ниже определении структуры я не уверен, что означают двоеточия после имен переменных (например, KeyPad:4). Это значит, что я должен прочитать 4 байта?

typedef struct
{
    UWORD StimType;
    UBYTE KeyBoard;
    UBYTE KeyPad:4;
    UBYTE Accept:4;
    long Offset;
} EVENT1;

В случае, если это полезно, абстрактный пример того, как я обращался к файлу в python, выглядит следующим образом:

from struct import unpack, calcsize

def get(ctype, size=1):
    """Reads and unpacks binary data into the desired ctype."""
    if size == 1:
        size = ''
    else:
        size = str(size)

    chunk = file.read(calcsize(size + ctype))
    return unpack(size + ctype, chunk)[0]

file = open("file.bin", "rb")
file.seek(1234)

var1 = get('i')
var2 = get('4l')
var3 = get('10s')

Ответы [ 4 ]

8 голосов
/ 28 сентября 2010

Перечисления: в языке нет перечислений. Были предложены различные идиомы, но ни один из них не получил широкого распространения. Наиболее простым (и в данном случае достаточным) решением является

TEEG_EVENT_TAB1 = 1
TEEG_EVENT_TAB2 = 2

Союзы: ctypes имеет союзы .

Синтаксис fieldname : n называется битовым полем и, да, действительно означает "это n больших битов". Опять же, у ctypes есть их .

2 голосов
/ 28 сентября 2010

Я не знаю ответа на все ваши вопросы, но для перечислений, в которых вам не требуется поиск по значению (то есть, просто использую его, чтобы избежать магических чисел), мне нравится использовать маленькийучебный класс.Обычный dict - еще один вариант, который отлично работает.Если вам нужен поиск по значению, вам может понадобиться другая структура.

class TeegType(object):
    TEEG_EVENT_TAB1 = 1
    TEEG_EVENT_TAB2 = 2

print TeegType.TEEG_EVENT_TAB1
0 голосов
/ 28 сентября 2010

Объявление C enum является синтаксической оболочкой для некоторого целочисленного типа.См. Всегда ли sizeof (enum) == sizeof (int)? .Величина int будет зависеть от конкретного компилятора Си.Вероятно, я бы начал с попытки 16 бит.

union резервирует блок памяти размером самого большого из содержащихся типов данных.Опять же, точный размер будет зависеть от реализации C, но я ожидаю, что 32-битная архитектура будет 32-битной или 64-битной, если она скомпилирована как собственный 64-битный код.Вообще говоря, вы сможете хранить содержимое объединения в целом или длинном Python независимо от того, что в нем было сохранено - указатель или смещение.

Более интересный вопрос: почемууказатель будет записан в файл на диске.Вы можете обнаружить, что поле union обрабатывается только как указатель, когда TEEG struct находится в памяти, но при записи на диск это всегда целочисленное смещение.

Что касается:4, как отметили несколько человек, это «битовые поля», означающие последовательность битов, некоторые из которых могут быть упакованы в один пробел.Если я правильно помню, битовые поля в C упакованы в int s, поэтому оба этих 4-битных поля будут упакованы в одно целое число.Они могут быть распакованы с соответствующим использованием операторов Python «&» (поразрядно и) и «>>» (смещение вправо).Опять же, то, как именно поля были упакованы в целое число, и размер самого целочисленного поля, будет зависеть от конкретной реализации языка Си.

Возможно, следующий фрагмент кода поможет вам:

SIZEOF_TEEG_TYPE = 2      # First guess for enum is two bytes
FMT_TEEG_TYPE = "h"       # Could be "b", "B", "h", "H", "l", "L", "q" or "Q"

SIZEOF_LONG = 4           # Use 8 in 64-bit Unix architectures
FMT_LONG = "l"            # Use "q" in 64-bit Unix architectures
                          # Life gets more interesting if you are reading 64-bit
                          # using 32-bit Python

SIZEOF_PTR_LONG_UNION = 4 # Use 8 in any 64-bit architecture
FMT_PTR_LONG_UNION = "l"  # Use "q" in any 64-bit architecture
                          # Life gets more interesting if you are reading 64-bit
                          # using 32-bit Python

SIZEOF_TEEG_STRUCT = SIZEOF_TEEG_TYPE + SIZEOF_LONG + SIZEOF_PTR_LONG_UNION
FMT_TEEG_STRUCT = FMT_TEEG_TYPE + FMT_LONG + FMT_PTR_LONG_UNION


# Constants for TEEG_EVENTs
TEEG_EVENT_TAB1 = 1
TEEG_EVENT_TAB2 = 2

.
.
.

# Read a TEEG structure
teeg_raw = file_handle.read( SIZEOF_TEEG_STRUCT )
teeg_type, teeg_size, teeg_offset = struct.unpack( FMT_TEEG_STRUCT, teeg_raw )

.
.
.

# Use TEEG_TYPE information
if teeg_type == TEEG_EVENT_TAB1:
    Do something useful

elif teeg_type == TEEG_EVENT_TAB2:
    Do something else useful

else:
    raise ValueError( "Encountered illegal TEEG_EVENT type %d" % teeg_type )
0 голосов
/ 28 сентября 2010

Что вам действительно нужно знать, это:

  1. Каков размер перечисления? . Вы будете использовать этот ответ для генерации кода распаковки.
  2. Каков размер союза? . Резюме: размер самого большого члена.
  3. Как вы справляетесь с этим указателем? Вы должны взглянуть на модуль ctypes. Для того, что вы делаете, может быть проще работать с модулем struct. В частности, он может работать с указателями, поступающими через C.
  4. Как вы приводите / преобразуете данные, прочитанные из структуры, в правильный тип для работы с Python? Вот почему я рекомендовал ctypes в пуле выше; этот модуль имеет функции для выполнения необходимых приведений.
...