struct.pack中的%d是什么意思?

2 投票
5 回答
3250 浏览
提问于 2025-04-16 02:57

我在阅读一段Python代码库时,遇到了一句让我困惑的话:

struct.pack( "<ii%ds"%len(value), ParameterTypes.String, len(value), value.encode("UTF8") )

我对其他部分都理解了,但对%d不太明白,而且我不明白为什么value的长度会被打包两次。

根据我的理解,这个结构会使用小端编码(<),里面会有两个整数(ii),接着是%d,然后是一个字符串(s)。

%d有什么特别的意义呢?

5 个回答

1

%d 的意思是它是一个字符串格式化的参数:
字符串格式化操作

把它拆开来看,"<ii%ds" % len(value) 就容易理解多了。它是在把字符串中的 %d 转换标志替换成 len(value) 的返回值,并且进行了适当的类型转换。

>>> str = "<ii%ds"
>>> str % 5
'<ii5s'
>>> str % 3
'<ii3s'
2

哎呀,真让人头疼……

@S.Lott: “我觉得数字并不是特别重要,因为Python通常会正确打包。” -1。别想当然,要去查查。没有数字只是意味着默认值是1。你觉得“打包通常正确”??也许你认为 struct.pack("s", foo)"%s" % foo 是一样的?其实并不是;文档上说:“对于's'格式字符,计数被解释为字符串的大小,而不是像其他格式字符那样的重复计数;例如,'10s'表示一个10字节的字符串,而'10c'表示10个字符。对于打包,字符串会被截断或用空字节填充,以适应大小。

@Brendan: -1value 不是数组(不管那是什么);它显然是一个unicode字符串……看看这里:value.encode("UTF8")

@Matt Ellen: 你引用的那行代码是严重错误的。如果 value 中有任何非ASCII字符,数据会丢失。

让我们来分析一下:

`struct.pack("<ii%ds"%len(value), ParameterTypes.String, len(value), value.encode("UTF8"))`  

通过移除第一个项目来减少问题空间

struct.pack("<i%ds"%len(value), len(value), value.encode("UTF8"))

现在假设 valueu'\xff\xff',那么 len(value) 是2。

v8 = value.encode('UTF8'),也就是 '\xc3\xbf\xc3\xbf'

注意 len(v8) 是4。明白了吗?

所以我们现在得到的是

struct.pack("<i2s", 2, v8)

数字2被打包成4个字节,02 00 00 00。4字节的字符串 v8 被截断(根据“2s”中的长度2)到长度2。数据丢失。失败。

正确的做法应该是:

v8 = value.encode('UTF8')
struct.pack("<ii%ds" % len(v8), ParameterTypes.String, len(v8), v8)
1

这其实是一个普通的字符串格式,用来创建结构体格式。

先把它当作普通字符串来看(暂时不考虑struct)……

"<ii%ds" % len(value)

比如说,如果这个值的可迭代对象的长度是4,那么这个字符串就会变成<ii4s。接下来,这个字符串会被传递给struct.pack,准备打包两个整数和一个长度为四个字节的字符串,这个字符串来自于value这个可迭代对象。

撰写回答