2015-05-16 67 views
0

我一直在這一整天,我似乎無法找到一個解決方案:(Python包裝int32但不起作用?

我有一個頭文件我想創建一個文件(我解析一個Python的obj文件輸出到二進制在我的C++遊戲引擎)被加載了數據。

這裏是網格報頭

struct MeshHeader 
{ 
    unsigned short _vertex_size; 
    uint32 _vertex_count; 
    unsigned short _index_buffer_count; 
    short _position_offset; 
    unsigned short _position_component_count; 
    short _uv_offset; 
    unsigned short _uv_component_count; 
    short _normal_offset; 
    unsigned short _normal_component_count; 
    short _tangent_offset; 
    unsigned short _tangent_component_count; 
    short _binormal_offset; 
    unsigned short _binormal_component_count; 
    short _colour_offset; 
    unsigned short _colour_component_count; 
}; 

的C++定義在哪裏UINT32基本上是從uint32_t的一個typedef從stdint.h .... 所以從這個角度來看,前三個成員變量分別是2個字節,4個字節,2個字節,是的?

這是我讀入結構

fread(&_header, sizeof(MeshHeader), 1, f); 

_vertex_size正確gets設置到56,但如果我改變它的數據類型爲UINT16(無符號短)_vertex_count被設置爲65536。它被正確設置到36.但爲什麼? 我正在使用pack("<I")函數(知道我的機器是小端)。

這是蟒蛇

f.write(pack('<H', self._vertex_size)) 
    f.write(pack('<I', self._vertex_count)) 
    f.write(pack('<H', self._index_buffer_count)) 
    f.write(pack('<h', self._position_offset)) 
    f.write(pack('<H', self._position_component_count)) 
    f.write(pack('<h', self._uv_offset)) 
    f.write(pack('<H', self._uv_component_count)) 
    f.write(pack('<h', self._normal_offset)) 
    f.write(pack('<H', self._normal_component_count)) 
    f.write(pack('<h', self._tangent_offset)) 
    f.write(pack('<H', self._tangent_component_count)) 
    f.write(pack('<h', self._binormal_offset)) 
    f.write(pack('<H', self._binormal_component_count)) 
    f.write(pack('<h', self._colour_offset)) 
    f.write(pack('<H', self._colour_component_count)) 

繼struct.pack功能(https://docs.python.org/2/library/struct.html)的規格收拾了代碼... H是無符號short(2個字節)我是無符號整數(4個字節)和h是一個短的(2個字節),它與我在C MeshHeader類中指定的完全一致,不是嗎?

過去幾個小時我一直拉出我的頭髮(而且我沒有太多它剩下的!)。關於可能發生什麼的任何建議?

這裏是頭文件的崇高文本快照3 BTW http://gyazo.com/e15942753819e695617390129e6aa879

+2

根據您的C++代碼的編譯方式,可能會在結構成員之間添加額外的字節,以便在32位或64位邊界上對齊它們,使計算機能夠比非-aligned。可能有一個編譯器選項來禁用這個,像'-StructPack' ... – martineau

+0

嘿謝謝你的回覆!我已經使用Visual Studio 2013社區版對32位和64位版本進行了試用。兩者都產生了我得到的相同結果。 –

+1

更改體系結構,特別是更大的單詞大小,可能無法解決此問題。您需要明確修改結構的打包方式。 –

回答

2

正如@martineau提到的,你看到的是C struct packing。編譯器在非字大小成員之間添加填充以優化內存訪問。您可以通過某些#pragma指令禁用此功能。對於Visual C,語法爲#pragma pack(1),如MSDN中所述。在以下示例中,我還使用pushpop將打包恢復到其先前的值。正確的打包對於有效的內存訪問非常重要,因此只能對寫入磁盤的結構進行更改。

// align on 1-byte 
#pragma pack(push, 1) 
struct MeshHeader 
{ 
    unsigned short _vertex_size; 
    uint32 _vertex_count; 
    unsigned short _index_buffer_count; 
    short _position_offset; 
    // ... 
}; 
// restore alignment 
#pragma pack(pop) 

注意,即使結構包裝避免,你可能仍然有問題與endianity。將結構寫入磁盤假設您在寫作者和讀者之間都有完整的控制權和知識。通過使用適當的序列化庫,可以使您的生活更輕鬆。有很多但支持C和Python的例子是protobufAvro

+0

我剛纔在最後一個回覆中遇到了這個!感謝雖然:) 而我只是強迫小尾巴,以確保它不是endian問題我的結局。我現在將刪除它。 謝謝所有:) –

+0

另一個快速問題 - 如果我要使所有這些整數,我的問題會消失嗎? (即我不需要擔心包推/彈出和填充問題?) 或者這會導致從32/64機器移植出現問題? –

+0

它將消失32位,但可能停留在64位,其中對齊是8個字節。你應該真的考慮'protobuf'或類似的東西。我認爲[Cap'n Proto](https://capnproto.org/)可以讓你甚至使用序列化的對象作爲普通的結構體,所以過渡應該很容易。 – kichik