2017-08-24 33 views
0

我正在使用外部提供的ctypes结构,它有一些字段定义为通用捕获所有字段。所述data字段的类型是基于mode字段的,如本示例所示:干净的方式将IEEE浮点数的字节表示插入Python ctypes uint32字段?

CONTAINS_ONE_FLOAT = 1 

class TestStruct(ctypes.Structure): 
    pass 

TestStruct._fields_ = [ 
    ('mode', ctypes.c_uint32), 
    ('data', ctypes.c_uint32 * 2) 
] 

我需要存储单精度(32位)浮点值在data每当mode设置为CONTAINS_ONE_FLOAT。在此模式下不使用data的第二个字。

我迄今为止只能使用ctypes casting来找出这种方法。看起来WAY太冗长了,但它起作用。

float_value = 42.42 
float_value_c = ctypes.c_float(float_value) 
float_value_cp = ctypes.POINTER(ctypes.c_float)(float_value_c) 
int_val_p = ctypes.cast(float_value_cp, ctypes.POINTER(ctypes.c_uint32)) 
int_val = int_val_p.contents 

x = TestStruct() 
x.mode = CONTAINS_ONE_FLOAT 
x.data[0] = int_val 

print("Should be 1110027796: " + str(x.data[0])) 

有没有更好的方法来做到这一点,不需要5个步骤?

+1

在一行中,您可以使用'ctypes.c_float.from_buffer(x.data).value = 42.42'。 – eryksun

回答

1

您可以使用struct

float_bytes = struct.pack('=f', float_value) 
x.data[0] = struct.unpack('=I', float_bytes)[0] 
+0

因为'unpack()'返回一个元组,所以我不得不在第二条语句的末尾添加'[0]'。否则,这是有效的,并不需要我修改提供给我的底层结构,而且不容易编辑。 –

1

你的描述通常是用C语言实现与union模式;你可以做同样的ctypes的:

CONTAINS_ONE_FLOAT = 1 

class TestStructData(ctypes.Union): 
    _fields_ = [ 
     ('one_float', ctypes.c_float), 
     ('two_dword', ctypes.c_uint32 * 2) 
    ] 

class TestStruct(ctypes.Structure): 
    _fields_ = [ 
     ('mode', ctypes.c_uint32), 
     ('data', TestStructData) 
    ] 

读/写您的浮动(或任何其他类型的存在),在TestStructData相应的字段读/写。

+0

这是最好的答案w.r.t.这些结构的原始设计,但不幸的是我的外部提供,我不能改变他们包括工会。我做了一个时间实验,这是结构包/解包解决方案的两倍。我也尝试过使用一个单独的联合只是为了转换,但它大约与结构包/解压缩一样快。 –