Python 打包 int32 但不起作用?
Python Packing int32 but doesn't work?
我整天都在做这个,但我似乎找不到解决办法:(
我有一个 header 用于我要创建的文件(我在 Python 中解析一个 obj 文件以输出为二进制数据以加载到我的 C++ 游戏引擎中)。
这是 Mesh 的 C++ 定义 Header
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;
};
其中 uint32 基本上是来自 stdint.h 的 uint32_t 的 typedef ...
那么由此来看,前三个member vars分别是2字节,4字节,2字节,对吧?
我是这样读入结构的
fread(&_header, sizeof(MeshHeader), 1, f);
_vertex_size 正确设置为 56,但 _vertex_count 设置为 65536。如果我将其数据类型更改为 uint16(unsigned short),它会正确设置为 36。但为什么呢?
我正在使用 pack("<I")
函数(知道我的机器是小端)。
这是我在python
中的打包代码
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 是无符号短整型(2 字节) I 是无符号整数(4 字节) h 是短整型(2 字节) ) 与我在 C MeshHeader class 中指定的完全匹配,不是吗?
过去几个小时我一直在拔头发(我的头发已经所剩无几了!)。对可能发生的事情有什么建议吗?
这是 Sublime Text 3 中 header 文件的快照
http://gyazo.com/e15942753819e695617390129e6aa879
如@martineau 所述,您看到的是 C struct packing. The compiler adds padding between non-word size members to optimize memory access. You can disable this with certain #pragma
directives. For Visual C, the syntax is #pragma pack(1)
as explained in MSDN。在下面的示例中,我还使用 push
和 pop
将打包恢复为之前的值。适当的打包对于有效的内存访问很重要,因此更改它应该只保留给您写入磁盘的结构。
// 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)
请注意,即使避免了 struct packing,您仍然可能遇到 endianity. Writing structures to disk assumes you have full control and knowledge ahead of time of both writer and reader. You can make your life easier by using a proper serialization library. There are many, but a few examples that support both C and Python are protobuf and Avro 的问题。
我整天都在做这个,但我似乎找不到解决办法:(
我有一个 header 用于我要创建的文件(我在 Python 中解析一个 obj 文件以输出为二进制数据以加载到我的 C++ 游戏引擎中)。
这是 Mesh 的 C++ 定义 Header
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;
};
其中 uint32 基本上是来自 stdint.h 的 uint32_t 的 typedef ... 那么由此来看,前三个member vars分别是2字节,4字节,2字节,对吧?
我是这样读入结构的
fread(&_header, sizeof(MeshHeader), 1, f);
_vertex_size 正确设置为 56,但 _vertex_count 设置为 65536。如果我将其数据类型更改为 uint16(unsigned short),它会正确设置为 36。但为什么呢?
我正在使用 pack("<I")
函数(知道我的机器是小端)。
这是我在python
中的打包代码 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 是无符号短整型(2 字节) I 是无符号整数(4 字节) h 是短整型(2 字节) ) 与我在 C MeshHeader class 中指定的完全匹配,不是吗?
过去几个小时我一直在拔头发(我的头发已经所剩无几了!)。对可能发生的事情有什么建议吗?
这是 Sublime Text 3 中 header 文件的快照 http://gyazo.com/e15942753819e695617390129e6aa879
如@martineau 所述,您看到的是 C struct packing. The compiler adds padding between non-word size members to optimize memory access. You can disable this with certain #pragma
directives. For Visual C, the syntax is #pragma pack(1)
as explained in MSDN。在下面的示例中,我还使用 push
和 pop
将打包恢复为之前的值。适当的打包对于有效的内存访问很重要,因此更改它应该只保留给您写入磁盘的结构。
// 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)
请注意,即使避免了 struct packing,您仍然可能遇到 endianity. Writing structures to disk assumes you have full control and knowledge ahead of time of both writer and reader. You can make your life easier by using a proper serialization library. There are many, but a few examples that support both C and Python are protobuf and Avro 的问题。