相当于 Python 中的 C 联合?

问题描述 投票:0回答:4

假设我在 C 中有以下代码:

union u_type
{
    uint32_t data;
    uint8_t  chunk[4];
} 32bitsdata;

32bitsdata.chunk[0] = some number;
32bitsdata.chunk[1] = some number;
32bitsdata.chunk[2] = some number;
32bitsdata.chunk[3] = some number;

printf("Data in 32 bits: %d\n", 32bitsdata.data);

我怎样才能在 ython 中做类似的事情?

我正在尝试读取一个二进制文件(逐字节) - 已经让它工作了,并将每 3 个字节组合成一个 int。听说 struct 可以解决这个问题,但我不太确定如何实现。

python union
4个回答
12
投票

ctypes怎么样?

from ctypes import (
        Union, Array, 
        c_uint8, c_uint32, 
        cdll, CDLL
) 

class uint8_array(Array):
    _type_ = c_uint8
    _length_ = 4

class u_type(Union):
    _fields_ = ("data", c_uint32), ("chunk", uint8_array)

# load printf function from Dynamic Linked Libary libc.so.6 (I'm using linux)
libc = CDLL(cdll.LoadLibrary('libc.so.6')._name)
printf = libc.printf

if __name__ == "__main__":
    # initialize union
    _32bitsdata = u_type()
    # set values to chunk
    _32bitsdata.chunk[:] = (1, 2, 3, 4)
    # and print it
    printf(b"Data in 32 bits: %d\n", _32bitsdata.data)

2
投票

这就是你要做的。首先,让我们创建我们需要的原始字节,我将作弊并使用

numpy

>>> import numpy as np
>>> arr = np.array((8,4,2,4,8), dtype=np.uint32)
>>> arr
array([8, 4, 2, 4, 8], dtype=uint32)
>>> raw_bytes = arr.tobytes()
>>> raw_bytes
b'\x08\x00\x00\x00\x04\x00\x00\x00\x02\x00\x00\x00\x04\x00\x00\x00\x08\x00\x00\x00'

这些可以很容易地从文件中读取。现在,使用

struct
模块很简单。我们使用 unsigned int 格式字符
'I'
:

>>> import struct
>>> list(struct.iter_unpack('I', raw_bytes))
[(8,), (4,), (2,), (4,), (8,)]

注意,每次迭代我们都会返回一个元组,因为我们的结构有一个成员,所以它是一个单例元组列表。但这对于进入扁平的Python列表来说是微不足道的:

>>> [t[0] for t in struct.iter_unpack('I', raw_bytes)]
[8, 4, 2, 4, 8]

另一种选择是将它们读入

array.array
:

>>> import array
>>> my_array = array.array('I', raw_bytes)
>>> my_array
array('I', [8, 4, 2, 4, 8])

1
投票

如果您正在进行奇特的数值操作,您可能无论如何都想使用 numpy 库,因此请考虑 numpy 的 ndarray 类型的“view”方法。可以通过视图数组查看和修改原始 ndarray。 >>> import numpy as np >>> a = np.uint32([1234567890]) >>> b = a.view(np.uint8) >>> print(a) [1234567890] >>> print(b) [210 2 150 73] >>> b[2] = 10 >>> print(*b) 210 2 10 73 >>> print(*a) 1225392850



0
投票
struct.unpack

来代替。 import struct chunk = bytearray() chunk.append(0x00) # some number chunk.append(0xc0) # some number chunk.append(0xff) # some number chunk.append(0xee) # some number # Convert to a 32-bit unsigned int. # You didn't specify the byte-order, so I'm using big-endian. # If you want little-endian instead, replace the '>' symbol by '<'. data = struct.unpack('>I', chunk)[0] # unpack returns a tupple, but we only need the first value print(hex(data)) # the terminal prints 0xc0ffee

© www.soinside.com 2019 - 2024. All rights reserved.