Python 结构体模块

Python struct模块用于提供一个简单的 Pythonic 接口来访问和操作 C 的结构数据类型。如果您需要处理 C 代码并且没有时间用 C 编写工具(因为它是一种低级语言),那么这可能是一个方便的工具。

该模块可以将 Python 值转换为 C 结构,反之亦然。C 结构被用作 Python字节对象,因为 C 中没有所谓的对象;仅字节大小的数据结构。

让我们了解如何使用此模块来获得 C 结构的 Python 接口。


Python 结构体模块方法

在本模块中,由于我们关注的是 C 结构,因此让我们看一下该模块为我们提供的一些函数。

struct.pack()

这用于将元素打包到 Python 字节字符串(字节对象)中。由于存储模式基于字节,因此基于 C 的程序可以使用pack()Python 程序中 , 的输出。

格式:struct.pack(格式, v1, v2, …)

v1, v2, … 是将被打包到字节对象中的值。它们代表 C 结构的字段值。由于具有字段的 C 结构n必须完全具有n值,因此参数必须与格式所需的值完全匹配。

这里,format指的是包装的格式。这是必需的,因为我们需要指定字节串的数据类型,因为它与 C 代码一起使用。下表列出了 的最常见值format我们需要每个值一种格式来指定它的数据类型。

格式 C 数据类型 Python类型
c 字符 长度为 1 的字符串
? _布尔 布尔值
h 短的 整数
l 长的 整数
i 整数 整数
f 漂浮 漂浮
d 双倍的 漂浮
s 字符[] 细绳

让我们用一些例子来理解这一点。

下面的代码片段使用 将 3 个整数 1、2 和 3 存储在一个字节对象中pack()由于在我的机器上整数的大小为 4 个字节,因此您会看到 3 个 4 字节的块,这对应于 C 中的 3 个整数。

import struct
 
# We pack 3 integers, so 'iii' is required
variable = struct.pack('iii', 1, 2, 3)
print(type(variable), variable)
 
variable_2 = struct.pack('iic', 1, 2, b'A')
print('\n', variable_2)

输出

<class 'bytes'> b'\x01\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00'
b'\x01\x00\x00\x00\x02\x00\x00\x00A'

struct.error如果未传递适当的类型, Python struct 模块将引发异常。

import struct
 
# Error!! Incorrect datatype assignment
variable = struct.pack('ccc', 1, 2, 3)
print(type(variable), variable)

输出

struct.error: char format requires a bytes object of length 1

struct.unpack()

Python struct 模块的此函数根据适当的格式将打包值解包为其原始表示形式。这将返回一个元组,其大小等于自字节对象被解包以提供元素以来传递的值的数量。

格式:struct.unpack(格式, 字符串)

string这根据格式说明符解包字节format

这是相反的struct.pack()让我们获取使用它生成的旧字节字符串之一,并尝试使用 取回传递给它的 python 值unpack()

import struct
 
byte_str = b'\x01\x00\x00\x00\x02\x00\x00\x00A'
 
# Using the same format specifier as before, since
# we want to get Python values for the same byte-string
tuple_vals = struct.unpack('iic', byte_str)
print(tuple_vals)

输出

(1, 2, b'A')

pack()正如您所看到的,实际上,只要我们对和 都使用相同的格式说明符,我们就可以从这个元组中获取旧的 Python 值unpack()


struct.calcsize()

此函数使用给定的格式说明符返回结构的字符串表示形式的总大小,以检索数据的类型并计算大小。

格式:struct.calcsize(fmt)

import struct
 
print('C Integer Size in Bytes:', struct.calcsize('i'))
print('Size of 3 characters in Bytes:', struct.calcsize('ccc'))

输出

C Integer Size in Bytes: 4
Size of 3 characters in Bytes: 3

struct.pack_into()

此函数用于将值打包到模块中可用的 Python 字符串缓冲区中ctypes

格式:struct.pack_into(fmt, buffer, offset, v1, v2, …)

与往常一样,这里fmt指的是格式说明符。buffer是字符串缓冲区,现在将包含指定的打包值。您还可以指定offset从基地址开始打包的位置。

这不会返回任何值,只是将值存储到buffer字符串中。

import struct
import ctypes
 
# We will create a string buffer having a size
# equal to that of a struct with 'iic' values.
buf_size = struct.calcsize('iic')
 
# Create the string buffer
buff = ctypes.create_string_buffer(buf_size)
   
# struct.pack() returns the packed data
struct.pack_into('iic', buff, 0, 1, 2, b'A')
 
print(buff)
 
# Display the contents of the buffer
print(buff[:])

输出

<ctypes.c_char_Array_9 object at 0x7f4bccef1040>
b'\x01\x00\x00\x00\x02\x00\x00\x00A'

事实上,我们在缓冲区字符串中获取了打包值。


struct.unpack_from()

与 类似unpack(),存在用于从缓冲区字符串中解包值的对应项。这与struct.pack_into().

格式:struct.unpack_from(fmt, buffer, offset)

这将返回一个值的元组,类似于struct.unpack().

import struct
import ctypes
 
# We will create a string buffer having a size
# equal to that of a struct with 'iic' values.
buf_size = struct.calcsize('iic')
 
# Create the string buffer
buff = ctypes.create_string_buffer(buf_size)
   
# struct.pack() returns the packed data
struct.pack_into('iic', buff, 0, 1, 2, b'A')
 
print(struct.unpack_from('iic', buff, 0))

输出

(1, 2, b'A')

结论

在这篇文章中,我们学习了如何使用Python struct模块来处理C类型的结构对象。

参考

  • JournalDev 关于 Python struct 模块的文章