给定映射到C结构的字节,如何通过C结构的变量名访问字节

时间:2018-01-31 21:51:49

标签: python python-3.x

(忍受我,我认为在C而不是Python,所以你可能会看到一些真正愚蠢的东西......)

我有许多(100 +)个不同的C structs,被引入Python(版本3.5.1)作为bytes,我希望能够使用原始的C结构访问#39;变量名。这是一个简单的例子。在Python中,我收到了这些bytes

# In Python:
example1_bytes = b'\x08\x09\x0a\x0b'

假设这些bytes由运行C的内容提供,使用以下格式的struct

// In C:
struct example1 {
  uint8_t val1;
  uint8_t val2;
  uint8_t val3;
  uint8_t val4; };

如何处理example1_bytes以便我可以像这样访问它们:

# In Python:
result = process_example1_bytes(example1_bytes)
print(result.val1)
# Prints "8"
print(result.val2)
# Prints "9"
# Et cetera

更进一步,如果C struct更复杂并包含数组和/或子结构,该怎么办?例如,像这样:

// In C:
struct substruct {
  uint8_t ss_val1;
  uint8_t ss_val2; };

struct example2 {
  uint8_t val1;
  uint8_t val2;
  struct substruct ss[8]; };

如何处理example2_bytes以便我可以像这样访问它们:

# In Python:
result = process_example2_bytes(example2_bytes)
print(result.val1)
print(result.ss[3].ss_val2)

我使用Python struct unpack进行了一些实验,它返回了元组,我认为是向正确方向迈出的一步,但是它还没有让我得到我想要的可用解决方案。我不确定是否需要走namedtuple路径或采取其他方向。

1 个答案:

答案 0 :(得分:3)

您正在寻找ctypes library,它允许您为复杂的底层C结构定义Python包装器。对于一个简单的类型:

import ctypes

example1_bytes = b'\x08\x09\x0a\x0b'

class Example1(ctypes.Structure):
    _fields_ = (
        ('val1', ctypes.c_uint8),
        ('val2', ctypes.c_uint8),
        ('val3', ctypes.c_uint8),
        ('val4', ctypes.c_uint8)
    )

ex1 = Example1.from_buffer_copy(example1_bytes)

print(ex1.val1, ex1.val2, ex1.val3, ex1.val4, sep='|')
# 8|9|10|11

更复杂的结构:

class substruct(ctypes.Structure):
    _fields_ = (
        ('ss_val1', ctypes.c_uint8),
        ('ss_val2', ctypes.c_uint8),
    )

class Example2(ctypes.Structure):
    _fields_ = (
        ('val1', ctypes.c_uint8),
        ('val2', ctypes.c_uint8),
        ('ss', substruct*8), #array type!
    )

注意,您使用乘法运算符定义大小为T的{​​{1}}类型的数组!:n

因此,与T*nStructures一起,它支持Arrays和指针,以及包含C程序员的各种好东西。

注意,您正在使用Unions个对象,这些对象是不可变的,在创建结构时需要复制。但是,如果您使用bytes,则不会需要底层缓冲区的副本!:

bytearray

但是,使用bytearray:

In [4]: example1_bytes
Out[4]: b'\x08\t\n\x0b'

In [5]: ex1.val2 = 99

In [6]: example1_bytes
Out[6]: b'\x08\t\n\x0b'