Python基础教程

005_struct二进制操作模块

struct二进制操作模块

struct在C语言中是关键字,用于定义结构体。

struct在Python语言中指的是模块,用于字节串(二进制数据)的打包与解包。打包之后的数据占用字节数与C语言中的struct结构体占用相同。

字节串的打包与解包

struct中常用两个方法

abytes=struct.pack(fmt,atup)
atup=struct.unpack(fmt,abytes)

fmt是类型字符,代表的意义同C语言中的整型、浮点等基础类型。

示例如下

import struct

pk=struct.pack("hhh",1,2,3)
print(type(pk))
print(pk)

unpk=struct.unpack("hhh",b'x01x00x02x00x03x00')
print(type(unpk))
print(unpk)

运行结果

C:UsershccmaAnaconda3python.exe E:/wkp01/p00/test01/atestpkg/t42.py
<class 'bytes'>
b'x01x00x02x00x03x00'
<class 'tuple'>
(1, 2, 3)

Process finished with exit code 0

format格式字符串

格式字符串是用来在打包和解包数据时指定预期布局的机制。 它们使用指定被打包/解包数据类型的 格式字符 进行构建。 此外,还有一些特殊字符用来控制 字节顺序,大小和对齐方式。

C 和 Python 值之间的按其指定类型的转换,类型对应表如下。

格式 C 类型 Python 类型 标准大小 注释
x 填充字节
c char 长度为 1 的字节串 1
b signed char 整数 1 (1), (2)
B unsigned char 整数 1 (2)
? _Bool bool 1 (1)
h short 整数 2 (2)
H unsigned short 整数 2 (2)
i int 整数 4 (2)
I unsigned int 整数 4 (2)
l long 整数 4 (2)
L unsigned long 整数 4 (2)
q long long 整数 8 (2)
Q unsigned long long 整数 8 (2)
n ssize_t 整数 (3)
N size_t 整数 (3)
e (6) 浮点数 2 (4)
f float 浮点数 4 (4)
d double 浮点数 8 (4)
s char[] 字节串
p char[] 字节串
P void * 整数 (5)

见官网(https://docs.python.org/zh-cn/3/library/struct.html)。

当有多个连续相同类型字符格式出现时,可以用数字表示重复出现次数。

示例如下

import struct

pk=struct.pack("4bh",1,2,3,4,1000)
print(pk)
unpk=struct.unpack("4bh",b'x01x02x03x04xe8x03')
print(unpk)

运行结果

C:UsershccmaAnaconda3python.exe E:/wkp01/p00/test01/atestpkg/t42.py
b'x01x02x03x04xe8x03'
(1, 2, 3, 4, 1000)

Process finished with exit code 0

大端与小端字节顺序

字节顺序指的是由多个字节表示的基本数据类型,其字节排列顺序。不同的电脑中,硬件处理方式不同(CPU),造成相同的变量数据在不同硬件上的解读顺序不同。

根据字节排列顺序不同,出现了大端和小端两种方式。

内存地址的表示中,左侧是低地址,右侧是高地址。

日常数字比如1000元,左侧是高数据位,右侧是低数据位。

大端模式(字节顺序),内存低地址位对应数据高位,内存高地址对应于数据低位。就是把日常数据整块与内存地址对齐。

小端模式(字节顺序),内存低地址位与数据低位对应,高地址与高数据位对应。

下面用基本数据类型short(占用两个字节)举例。

import struct

pk=struct.pack("<h",5)
print(pk)                # 内存中两个字节,05出现在左侧,小端
pk=struct.pack(">h",5)
print(pk)

pk=struct.pack("h",1000)
print(pk)                # 本电脑是小端模式
unpk=struct.unpack("<h",b'xe8x03')
print(unpk)              # 用小端模式解读时正确
unpk=struct.unpack(">h",b'xe8x03')
print(unpk)

运行结果

C:UsershccmaAnaconda3python.exe E:/wkp01/p00/test01/atestpkg/t42.py
b'x05x00'
b'x00x05'
b'xe8x03'
(1000,)
(-6141,)

Process finished with exit code 0

根据下表,格式字符串的第一个字符可用于指示打包数据的字节顺序,大小和对齐方式:

字符 字节顺序 大小 对齐方式
@ 按原字节 按原字节 按原字节
= 按原字节 标准
< 小端 标准
> 大端 标准
! 网络(=大端) 标准

Python判断系统大端或小端

直接使用系统函数

import sys

print(sys.byteorder.capitalize())     # Little

手动判断

import struct

val = 0x12345678
pk = struct.pack('i',val)
print(len(pk))
print(hex(pk[0]))
print(hex(pk[1]))
print(hex(pk[2]))
print(hex(pk[3]))

hex_pk = hex(pk[0])
if hex_pk == '0x78':
    print('小端')
elif hex_pk == '0x12':
    print('大端')

运行结果

C:UsershccmaAnaconda3python.exe E:/wkp01/p00/test01/atestpkg/t42.py
4
0x78
0x56
0x34
0x12
小端

Process finished with exit code 0

一些问题

Python显示出来的内存(十六进制)不准确(与常规理解有差别)。比如0x12345678,打包后的结果显示的并不是x12x34x56x78,但是数据在实际内存中是正确的。

import struct

val = 0x12345678
pk = struct.pack('>i',val)

print(pk)
print(hex(pk[0]),hex(pk[1]),hex(pk[2]),hex(pk[3]))

运行结果

C:UsershccmaAnaconda3python.exe E:/wkp01/p00/test01/atestpkg/t42.py
b'x124Vx'
0x12 0x34 0x56 0x78

Process finished with exit code 0

更多内容请参考官方标准库手册。

这篇文章对您有用吗?

我们要如何帮助您?