2010-09-28 53 views
4

我想弄清楚一些C代碼,以便我可以將它移植到python中。該代碼用於讀取專有的二進制數據文件格式。到目前爲止它已經很簡單 - 它主要是結構,我一直在使用struct庫來從文件中請求特定的ctypes。然而,我只是想到了這一點的代碼,我不知道如何在python中實現它。特別是,我不知道如何處理enumunion在Python中實現C的枚舉和聯合

#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') 

+0

因爲我真的不知道蟒蛇,我不能幫你那裏,但變量名後的冒號表示的howmany位用於存放它(所以keyPad和Accept共享一個字節,KeyPad位於前四位,Accept位於最後四位) – Grizzly 2010-09-28 16:37:37

+0

在Python中不需要聯合,因爲它不使用嚴格的類型檢查。在你上面的例子中,你可以把這個地址綁定到一個對象上,並把一個長的地址綁定到同一個名字上。 – 2010-09-28 17:16:34

+0

@Micael Mior。 Python __does__在運行時進行嚴格的類型檢查。儘管你可以將兩個不同的值綁定到同一個名字,但你永遠不可以讓它們擁有__共享同一個地址___這就是C中的union。 – aaronasterling 2010-09-28 17:47:03

回答

8

枚舉:語言中沒有枚舉。已經提出了各種成語,但沒有一種真的很普遍。最直接的(在這種情況下足夠)的解決方案是

TEEG_EVENT_TAB1 = 1 
TEEG_EVENT_TAB2 = 2 

聯盟:ctypes具有unions

fieldname : n語法被稱爲位字段,是的,的確,這意味着「這是n位大」。再次,ctypes有them

2

我不知道答案,所有的問題,但對於不需要按值查找的枚舉(僅僅使用它來避免幻數),我喜歡使用一個小類。一個正規字典是另一個可以正常工作的選項。如果您需要按值查找,您可能需要其他結構。

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

print TeegType.TEEG_EVENT_TAB1 
0

你真正需要知道的是:

  1. What is the size of an enum?。您將使用此答案來生成解包代碼。
  2. What is the size of a union?。總結:最大成員的大小。
  3. 你如何處理該指針?你應該看看​​模塊。對於你正在做的事情,使用模塊比使用struct模塊更容易。特別是,它可以通過指針C到達。
  4. 如何強制/將從結構中讀取的數據轉換爲正確的類型以便在python中使用?這就是爲什麼我在上面的項目中推薦​​;此模塊具有執行必要演員的功能。
0

C enum聲明是圍繞某些整數類型的語法包裝。見Is the sizeof(enum) == sizeof(int), always?int有多大取決於特定的C編譯器。我可能會開始嘗試16位。

union保留一個內存塊,其大小爲所包含數據類型中最大的一個。再一次,確切的大小將取決於C的實現,但我希望32位體系結構有32位,如果編譯爲本機64位代碼,則會有64位。一般來說,無論保存的內容是指針還是偏移量,您都可以將聯合的內容存儲在Python整數或長整型中。

一個更有趣的問題是爲什麼指針會被寫入磁盤文件。當TEEGstruct位於內存中時,您可能會發現union字段僅作爲指針處理,但寫入磁盤時,它始終爲整數偏移量。

至於:4符號,正如幾個人已經指出的那樣,這些是「比特字段」,意思是一系列比特,其中幾個可以被打包到一個空間中。如果我沒有記錯,C中的位域被打包到int s中,所以這兩個4位字段將被打包成一個整數。可以適當使用Python的「&」(按位和)和「>>」(右移)運算符來解壓縮它們。同樣,這些字段如何被打包到整數中,以及整數字段本身的大小將取決於具體的C實現。

也許下面的代碼片段將幫助您:

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)