※注(py3はもっとシンプルな方法があった)
>>> import ctypes
>>> f = ctypes.c_float(0.5)
>>> f
c_float(0.5)
>>> memoryview(f).tobytes()
b'\x00\x00\x00?'
>>> memoryview(f).cast('B', shape=(4,))[3] = 0x3e
>>> f
c_float(0.125)
>>> memoryview(f).cast('B', shape=(4,))[3] = 0x40
>>> f
c_float(2.0)
>>> memoryview(f).cast('B', shape=(4,))[:] = bytes([0x3a, 0xcd, 0x13, 0xbf])
>>> f
c_float(-0.5773502588272095)
ctyes の使い方をいつも忘れるのでメモ。
a = 0.5 のときの a のメモリ上のバイト列を観たい。
>>> import ctypes
>>> a = ctypes.c_float(0.5)
>>> a
c_float(0.5)
>>> a.value
0.5
>>> ctypes.cast(ctypes.byref(a), ctypes.POINTER(ctypes.c_float))
<__main__.LP_c_float object at 0x000001FF2A2F59C8>
>>> ctypes.cast(ctypes.byref(a), ctypes.POINTER(ctypes.c_char))
<ctypes.LP_c_char object at 0x000001FF2A2F5B48>
>>> ctypes.cast(ctypes.byref(a), ctypes.POINTER(ctypes.c_char))[0:4]
b'\x00\x00\x00?'
[0:4] で範囲指定しておかないと怒られる。([:]だとエラー)
出力が判り易い様に修正。
>>> b = lambda f: [f'{b:02x}' for b in ctypes.cast(ctypes.byref(ctypes.c_float(f)), ctypes.POINTER(ctypes.c_char))[0:4]]
>>> b(0.5)
['00', '00', '00', '3f']
ついでにその他の数値は、
>>> b(0.25)
['00', '00', '80', '3e']
>>> b(0.866)
['2d', 'b2', '5d', '3f']
>>> b(0.433)
['2d', 'b2', 'dd', '3e']
>>> b(0.216)
['1b', '2f', '5d', '3e']
>>> b(0.0)
['00', '00', '00', '00']
>>> b(1.0)
['00', '00', '80', '3f']
逆も確認(バイト列から float)。
>>> f = lambda b: ctypes.cast(ctypes.create_string_buffer(b), ctypes.POINTER(ctypes.c_float))[0]
>>> f(b'\x2d\xb2\x5d\x3f')
0.8659999966621399
>>> f(b'\x2d\xb2\xdd\x3e')
0.43299999833106995
>>> f(b'\x2d\xb2\x5d\x3e')
0.21649999916553497
>>> f(b'\x3a\xcd\x13\xbf')
-0.5773502588272095