如何将整数解释为浮点数
How to interpret a integer as a float
我正在尝试使用用 C# 编写的 DLL 与激光通信。我使用 ctypes 模块成功加载了 DLL 函数。我要使用的函数有一个如下所示的声明:
LONG LJV7IF_GetStorageData( LONG lDeviceId,
LJV7IF_GET_STORAGE_REQ* pReq,
LJV7IF_STORAGE_INFO* pStorageInfo,
LJV7IF_GET_STORAGE_RSP* pRsp,
DWORD* pdwData,
DWORD dwDataSize );
我想通过双字指针 pdwData 访问数据。激光器通过如下所示的结构发送其存储数据:
Bytes | Meaning | Types
0-3 | time | dword
4 | judgment | byte
5 | meas info | byte
... | ... | ...
8-11 | data | float
我是这样使用函数的:
self.dll = WinDLL( "LJV7_IF.dll" )
self._getStoredData = self.dll.LJV7IF_GetStorageData
self._getStoredData.restype = c_int32
self._getStoredData.argstypes = [ c_int32,
POINTER( GET_STORAGE_REQ ),
POINTER( STORAGE_INFO ),
POINTER( GET_STORAGE_RSP ),
POINTER( c_uint32 ),
c_uint32 ]
dataSize = 132
dataBuffer = c_uint32 * ( dataSize / 4 )
outputData_p = POINTER( c_uint32 )( dataBuffer() )
self._getStoredData( deviceID,
byref( myStruct ),
byref( storageInfo ),
byref( storageResponse ),
outputData_p ),
dataSize )
为简洁起见,myStruct、storageInfo 和 storageResponse 没有详细说明(它们在其他 DLL 函数调用中使用,并且它们似乎工作得很好)。
我的问题是当我尝试访问 outputData_p[ 2 ]
、python return 一个整数时,比如 1066192077。这正是我问他的。但我希望那个 int 是 interpreted/converted 作为一个浮点数,它应该是 1.1 或类似的东西(不记得确切的值)。将它转换为浮动不起作用(我得到 1066192077.00 ),也使用 hex() -> bytes() -> struct.unpack( )
。我能做什么??
注意:如果您是在搜索如何将整数转换为单精度浮点数时到达此处,请忽略此答案的其余部分并仅使用 J.F 中的代码。塞巴斯蒂安的评论。它使用 struct 模块而不是 ctypes,后者更简单且始终可用,而 ctypes 可选地包含在 Python 的标准库中:
import struct
def float_from_integer(integer):
return struct.unpack('!f', struct.pack('!I', integer))[0]
assert float_from_integer(1066192077) == 1.100000023841858
您可以使用 ctypes from_buffer
方法将数组解释为不同的类型。通常,您可以将任何对象传递给具有可写缓冲区接口的此方法,而不仅仅是 ctypes 实例——例如 bytearray
或 NumPy 数组。
例如:
>>> from ctypes import *
>>> int_array = (c_int * 4)(1, 2, 3, 4)
>>> n_doubles = sizeof(int_array) // sizeof(c_double)
>>> array_t = c_double * n_doubles
>>> double_array = array_t.from_buffer(int_array)
仍然是相同的字节,只是重新解释为两个 8 字节的双精度数:
>>> bytes(double_array)
b'\x01\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x04\x00\x00\x00'
>>> double_array[:]
[4.2439915824e-314, 8.4879831653e-314]
由于这个数组是通过调用 from_buffer
创建的,而不是 from_buffer_copy
,它实际上是一个与原始数组共享相同缓冲区的视图。例如,如果将最后 2 个整数移到前面,double_array
中的值也会被交换:
>>> int_array[:] = [3, 4, 1, 2]
>>> double_array[:]
[8.4879831653e-314, 4.2439915824e-314]
请注意,您的示例代码有错字。定义函数参数类型的属性名称是 argtypes
,而不是 argstypes
:
self._getStoredData.argstypes = [ c_int32,
^^^^^^^^^
定义此原型并非绝对必要,但建议这样做。它使 ctypes 在调用函数时为每个参数调用相应的 from_param
方法。如果没有原型,默认参数处理接受 ctypes 实例并自动将字符串转换为 char *
或 wchar_t *
并将整数转换为 C int
值;否则它会引发 ArgumentError
。
您可以按如下方式定义打包(即没有对齐填充)数据记录:
class LaserData(Structure):
_pack_ = 1
_fields_ = (('time', c_uint),
('judgement', c_byte),
('meas_info', c_byte * 3),
('data', c_float))
下面是一个示例 class,它将通用数据参数类型定义为 POINTER(c_byte)
,并将结果 returns 定义为由设备实例确定的记录数组。显然,这只是 class 实际应该如何定义的要点,因为我对此 API.
几乎一无所知
class LJV7IF(object):
# loading the DLL and defining prototypes should be done
# only once, so we do this in the class (or module) definition.
_dll = WinDLL("LJV7_IF")
_dll.LJV7IF_Initialize()
_dll.LJV7IF_GetStorageData.restype = c_long
_dll.LJV7IF_GetStorageData.argtypes = (c_long,
POINTER(GET_STORAGE_REQ),
POINTER(STORAGE_INFO),
POINTER(GET_STORAGE_RSP),
POINTER(c_byte),
c_uint)
def __init__(self, device_id, record_type):
self.device_id = device_id
self.record_type = record_type
def get_storage_data(self, count):
storage_req = GET_STORAGE_REQ()
storage_info = STORAGE_INFO()
storage_rsp = GET_STORAGE_RSP()
data_size = sizeof(self.record_type) * count
data = (c_byte * data_size)()
result = self._dll.LJV7IF_GetStorageData(self.device_id,
byref(storage_req),
byref(storage_info),
byref(storage_rsp),
data,
data_size)
if result < 0: # assume negative means an error.
raise DeviceError(self.device_id) # an Exception subclass.
return (self.record_type * count).from_buffer(data)
例如:
if __name__ == '__main__':
laser = LJV7IF(LASER_DEVICE_ID, LaserData)
for record in laser.get_storage_data(11):
print(record.data)
我正在尝试使用用 C# 编写的 DLL 与激光通信。我使用 ctypes 模块成功加载了 DLL 函数。我要使用的函数有一个如下所示的声明:
LONG LJV7IF_GetStorageData( LONG lDeviceId,
LJV7IF_GET_STORAGE_REQ* pReq,
LJV7IF_STORAGE_INFO* pStorageInfo,
LJV7IF_GET_STORAGE_RSP* pRsp,
DWORD* pdwData,
DWORD dwDataSize );
我想通过双字指针 pdwData 访问数据。激光器通过如下所示的结构发送其存储数据:
Bytes | Meaning | Types
0-3 | time | dword
4 | judgment | byte
5 | meas info | byte
... | ... | ...
8-11 | data | float
我是这样使用函数的:
self.dll = WinDLL( "LJV7_IF.dll" )
self._getStoredData = self.dll.LJV7IF_GetStorageData
self._getStoredData.restype = c_int32
self._getStoredData.argstypes = [ c_int32,
POINTER( GET_STORAGE_REQ ),
POINTER( STORAGE_INFO ),
POINTER( GET_STORAGE_RSP ),
POINTER( c_uint32 ),
c_uint32 ]
dataSize = 132
dataBuffer = c_uint32 * ( dataSize / 4 )
outputData_p = POINTER( c_uint32 )( dataBuffer() )
self._getStoredData( deviceID,
byref( myStruct ),
byref( storageInfo ),
byref( storageResponse ),
outputData_p ),
dataSize )
为简洁起见,myStruct、storageInfo 和 storageResponse 没有详细说明(它们在其他 DLL 函数调用中使用,并且它们似乎工作得很好)。
我的问题是当我尝试访问 outputData_p[ 2 ]
、python return 一个整数时,比如 1066192077。这正是我问他的。但我希望那个 int 是 interpreted/converted 作为一个浮点数,它应该是 1.1 或类似的东西(不记得确切的值)。将它转换为浮动不起作用(我得到 1066192077.00 ),也使用 hex() -> bytes() -> struct.unpack( )
。我能做什么??
注意:如果您是在搜索如何将整数转换为单精度浮点数时到达此处,请忽略此答案的其余部分并仅使用 J.F 中的代码。塞巴斯蒂安的评论。它使用 struct 模块而不是 ctypes,后者更简单且始终可用,而 ctypes 可选地包含在 Python 的标准库中:
import struct
def float_from_integer(integer):
return struct.unpack('!f', struct.pack('!I', integer))[0]
assert float_from_integer(1066192077) == 1.100000023841858
您可以使用 ctypes from_buffer
方法将数组解释为不同的类型。通常,您可以将任何对象传递给具有可写缓冲区接口的此方法,而不仅仅是 ctypes 实例——例如 bytearray
或 NumPy 数组。
例如:
>>> from ctypes import *
>>> int_array = (c_int * 4)(1, 2, 3, 4)
>>> n_doubles = sizeof(int_array) // sizeof(c_double)
>>> array_t = c_double * n_doubles
>>> double_array = array_t.from_buffer(int_array)
仍然是相同的字节,只是重新解释为两个 8 字节的双精度数:
>>> bytes(double_array)
b'\x01\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x04\x00\x00\x00'
>>> double_array[:]
[4.2439915824e-314, 8.4879831653e-314]
由于这个数组是通过调用 from_buffer
创建的,而不是 from_buffer_copy
,它实际上是一个与原始数组共享相同缓冲区的视图。例如,如果将最后 2 个整数移到前面,double_array
中的值也会被交换:
>>> int_array[:] = [3, 4, 1, 2]
>>> double_array[:]
[8.4879831653e-314, 4.2439915824e-314]
请注意,您的示例代码有错字。定义函数参数类型的属性名称是 argtypes
,而不是 argstypes
:
self._getStoredData.argstypes = [ c_int32,
^^^^^^^^^
定义此原型并非绝对必要,但建议这样做。它使 ctypes 在调用函数时为每个参数调用相应的 from_param
方法。如果没有原型,默认参数处理接受 ctypes 实例并自动将字符串转换为 char *
或 wchar_t *
并将整数转换为 C int
值;否则它会引发 ArgumentError
。
您可以按如下方式定义打包(即没有对齐填充)数据记录:
class LaserData(Structure):
_pack_ = 1
_fields_ = (('time', c_uint),
('judgement', c_byte),
('meas_info', c_byte * 3),
('data', c_float))
下面是一个示例 class,它将通用数据参数类型定义为 POINTER(c_byte)
,并将结果 returns 定义为由设备实例确定的记录数组。显然,这只是 class 实际应该如何定义的要点,因为我对此 API.
class LJV7IF(object):
# loading the DLL and defining prototypes should be done
# only once, so we do this in the class (or module) definition.
_dll = WinDLL("LJV7_IF")
_dll.LJV7IF_Initialize()
_dll.LJV7IF_GetStorageData.restype = c_long
_dll.LJV7IF_GetStorageData.argtypes = (c_long,
POINTER(GET_STORAGE_REQ),
POINTER(STORAGE_INFO),
POINTER(GET_STORAGE_RSP),
POINTER(c_byte),
c_uint)
def __init__(self, device_id, record_type):
self.device_id = device_id
self.record_type = record_type
def get_storage_data(self, count):
storage_req = GET_STORAGE_REQ()
storage_info = STORAGE_INFO()
storage_rsp = GET_STORAGE_RSP()
data_size = sizeof(self.record_type) * count
data = (c_byte * data_size)()
result = self._dll.LJV7IF_GetStorageData(self.device_id,
byref(storage_req),
byref(storage_info),
byref(storage_rsp),
data,
data_size)
if result < 0: # assume negative means an error.
raise DeviceError(self.device_id) # an Exception subclass.
return (self.record_type * count).from_buffer(data)
例如:
if __name__ == '__main__':
laser = LJV7IF(LASER_DEVICE_ID, LaserData)
for record in laser.get_storage_data(11):
print(record.data)