python ctype _pack_ vs g ++ #pragma pack

时间:2016-06-25 10:32:33

标签: python ctypes

我打算将这样的结构序列化为"压缩"二进制:

#include <cstdio>
#include <iostream>

using namespace std;

#define print(x) cout << x << endl

#pragma pack(1)

class Foo {
    uint32_t a: 1;
    uint32_t b: 2;
    uint32_t c: 5;
    uint64_t d;
};

int main() {
    print(sizeof(char));
    print(sizeof(Foo));
    return 0;
};

这里效果很好,班级的大​​小&#34; Foo&#34;是9,这正是我想要的。

但是当我尝试用Python ctypes lib重新实现它时,一切都会出错。

import ctypes
from io import BytesIO
from ctypes import *
from binascii import hexlify

class RawMessage(ctypes.Structure):
    _pack_ = 1
    _fields_ = [
        ('a', ctypes.c_uint, 1),
        ('b', ctypes.c_uint, 2),
        ('c', ctypes.c_uint, 5),
        ('d', ctypes.c_ulong),
    ]


def dump(o):
    s = BytesIO()
    s.write(o)
    s.seek(0)
    return hexlify(s.read())


if __name__ == '__main__':
    m = RawMessage()
    m.a = m.b = m.c = m.d = 0xFFFFFFFFFFFFFFFF
    print ctypes.sizeof(m)
    print dump(m)

RawMessage的大小是12.我想&#34; &#34;财产根本不起作用。消息m的二进制表示是&#34; ff000000ffffffffffffffff&#34;。

这是一个令人困惑的问题。请帮帮我。

感谢。

1 个答案:

答案 0 :(得分:0)

如果您希望RawMessage的sizeof为9,则需要将c_uint8用于位字段,将c_ulonglong用于无符号64位字段(您使用{{1}这只是4字节/ 32位)。

python 3代码,但这个想法应该转换为python 2.7:

c_ulong

输出:

#!/usr/bin/python3
import ctypes
import io
import binascii

class RawMessage(ctypes.Structure):
    _pack_ = 1
    _fields_ = [
        ('a', ctypes.c_uint8 , 1),
        ('b', ctypes.c_uint8 , 2),
        ('c', ctypes.c_uint8 , 5),
        ('d', ctypes.c_ulonglong),
    ]

def dump(o):
    s = io.BytesIO()
    s.write(o)
    s.seek(0)
    return binascii.hexlify(s.read())

def bin_dump(byte_buff):
    s_buff = list()
    for abyte in byte_buff:
        s_buff.append("{:08b}".format(abyte))
    return "".join(s_buff)

if __name__ == '__main__':
    m = RawMessage()
    m.a = 1  # 1
    m.b = 1  # 01
    m.c = int('11111', 2)  # 11111
    m.d = 0x7ffffffffffffffe  # 1st and last bit set to 0

    # note : m.a, m.b and m.c should read: 
    # 11111 01 1 -> 11111011 -> 0xfb

    print("size of RawMessage: {}".format(ctypes.sizeof(m)))
    buf = (ctypes.c_char * ctypes.sizeof(m)).from_buffer_copy(m)
    bytes_buff = bytes(buf)
    print("buffer: {}".format(bytes_buff))

    #print(bin_dump(bytes_buff))

    print(dump(m))