python3中的Struct模块打包和解包C语言中的结构体,及二进制数据的处理

本文深入探讨C语言结构体与Python数据类型对比,详细解析使用Python的struct模块进行数据打包与解包的过程,包括计算格式字符串所占字节大小及截取特定值的方法,并强调了32位与64位系统数据类型支持的区别。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

最终在学习有关网络通讯socket相关知识,涉及知识如下目录,整理出来方便后续查阅:


1.C语言结构体相关知识

参考文章地址:
http://c.biancheng.net/view/2031.html

  • 结构体是一种集合,它里面包含了多个变量或数组,它们的类型可以相同,也可以不同,每个这样的变量或数组都称为结构体的成员(Member)。
  • 像 int、float、char 等是由C语言本身提供的数据类型,不能再进行分拆,我们称之为基本数据类型;而结构体可以包含多个基本类型的数据,也可以包含其他的结构体,我们将它称为复杂数据类型或构造数据类型
struct stu{
    char *name;  //姓名
    int num;  //学号
    int age;  //年龄
    char group;  //所在学习小组
    float score;  //成绩
};

2.C & Python数据类型的比较

参考文章地址:
https://docs.python.org/2/library/struct.html#struct-format-strings

c语言每种数据类型有个简称(暂时这么理解),例如x/c/b/B,每个字母代表C和Python不同的数据类型。每种类型在不同语言里面的数据大小可能不一样,但转换为bytes之后,最终尺寸大小是一样的。最终Notes里面的含义,参考如上连接说明
在这里插入图片描述


3.使用python打包struct.pack()

通过如上介绍,我们大致可以理解为,把C语言的结构体(多种数据类型组合到一起)打包之后,变成一个二进制字符串,最终python语言能读懂C语言传递过来数据的含义了。

struct模块介绍:
英文:https://docs.python.org/3/library/struct.html
中文翻译:https://blog.youkuaiyun.com/lakerszhy/article/details/70214202

def pack(fmt, *args): # known case of _struct.pack      # 源码: 
    """
    pack(fmt, v1, v2, ...) -> bytes
    
    Return a bytes object containing the values v1, v2, ... packed according
    to the format string fmt.  See help(struct) for more on format strings.
    """
    return b""

将v1,v2等参数的值进行一层包装,包装的方法由fmt指定。被包装的参数必须严格符合fmt。最后返回一个包装后的字符串。

(1)fmt包装的方法

在这里插入图片描述

(2)打包的case
import struct

buffer = struct.pack("ihb", 1, 2, 3)
print(repr(buffer))
print(struct.unpack("ihb", buffer))

# 输出:
b'\x01\x00\x00\x00\x02\x00\x03'
(1, 2, 3)
(3)计算fmt类型所占字节大小

源码:

def calcsize(fmt): # known case of _struct.calcsize
    """
    calcsize(fmt) -> integer
    
    Return size in bytes of the struct described by the format string fmt.
    """
    return 0

案例:


import struct
length = struct.calcsize("ihb")    # 计算给定的格式(fmt)占用多少字节的内存
print(length)

# 输出 7  ,参照C & python 类型转换表,对应i:4bytes, h:2bytest, b:1bytes

(4)根据每个变量所占bytes大小,截取需要的value
import struct

buffer = struct.pack("ihb", 1, 2, 3)
print(len(buffer))       # 计算打包之后字节流的大小

length_1 = struct.calcsize("i")
value_1_bytes = buffer[:length_1]
print(length_1, value_1_bytes)

length_2 = struct.calcsize("h")
value_2_bytes = buffer[length_1:length_1 + length_2]
print(length_2, value_2_bytes)

length_3 = struct.calcsize("b")
value_3_bytes = buffer[length_1 + length_2:length_1 + length_2 + length_3]
print(length_3, value_3_bytes)
7    # 组包之后的字节流所占7个字节长度
4 b'\x01\x00\x00\x00'
2 b'\x02\x00'
1 b'\x03'

# (1,2,3)打包之后的数据为b'\x01\x00\x00\x00\x02\x00\x03'

通过如上的计算,我们发现通过buffer[:xxx]方式截取的内容,是按照字节去截取的,因为打包之后的数据共计7个字节,且value1,value2,value3三个值的顺序是固定的,所以可以根据每个value所占字节的大小去截取你需要value的内容。但是所截取的仅仅是二进制的字节流,还需要再解包才能得到最终的十进制数据。


4.使用python解包struct.unpack()

def unpack(fmt, string): # known case of _struct.unpack
    """
    unpack(fmt, buffer) -> (v1, v2, ...)
    
    Return a tuple containing values unpacked according to the format string
    fmt.  The buffer's size in bytes must be calcsize(fmt). See help(struct)
    for more on format strings.
    """
    pass

通过源码,发现解包与打包类似,都需要输入解包方式fmt,以及需要解包的二进制字节流

import struct

buffer = struct.pack("ihb", 1, 2, 3)
print(len(buffer))

length_1 = struct.calcsize("i")
value_1_bytes = buffer[:length_1]
value_1_decode = struct.unpack("i", buffer[:length_1])
print(length_1, value_1_bytes, value_1_decode)

length_2 = struct.calcsize("h")
value_2_bytes = buffer[length_1:length_1 + length_2]
value_2_decode = struct.unpack("h", buffer[length_1:length_1 + length_2])
print(length_2, value_2_bytes, value_2_decode)

length_3 = struct.calcsize("b")
value_3_bytes = buffer[length_1 + length_2:length_1 + length_2 + length_3]
value_3_decode = struct.unpack("b", buffer[length_1 + length_2:length_1 + length_2 + length_3])
print(length_3, value_3_bytes, value_3_decode)

7
4 b'\x01\x00\x00\x00' (1,)
2 b'\x02\x00' (2,)
1 b'\x03' (3,)

5.注意事项:32位&64位系统支持的数据类型不同

在32位系统里面,C语言不支持q & Q数据类型,因为32系统存储的字节最长4位,共计32个比特位(bit);64位系统,最长支持8个字节,共计64个比特位(bit);

参考文章https://www.cnblogs.com/xywq/p/7594457.html
https://blog.youkuaiyun.com/toontong/article/details/4391305

在这里插入图片描述

所以如果组包是在32位系统组包的,解包不能在64位系统解包,否者结果也是错误的!!

本文参考地址:
https://blog.youkuaiyun.com/JIA227/article/details/73135944
https://blog.youkuaiyun.com/weiwangchao_/article/details/80395941

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

hello-alien

您的鼓励,是我最大的支持!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值