目录
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
更多内容请参考官方标准库手册。