struct.pack中的%d是什么意思?
我在阅读一段Python代码库时,遇到了一句让我困惑的话:
struct.pack( "<ii%ds"%len(value), ParameterTypes.String, len(value), value.encode("UTF8") )
我对其他部分都理解了,但对%d
不太明白,而且我不明白为什么value
的长度会被打包两次。
根据我的理解,这个结构会使用小端编码(<
),里面会有两个整数(ii
),接着是%d
,然后是一个字符串(s
)。
%d
有什么特别的意义呢?
5 个回答
%d
的意思是它是一个字符串格式化的参数:
字符串格式化操作
把它拆开来看,"<ii%ds" % len(value)
就容易理解多了。它是在把字符串中的 %d 转换标志替换成 len(value)
的返回值,并且进行了适当的类型转换。
>>> str = "<ii%ds"
>>> str % 5
'<ii5s'
>>> str % 3
'<ii3s'
哎呀,真让人头疼……
@S.Lott: “我觉得数字并不是特别重要,因为Python通常会正确打包。” -1。别想当然,要去查查。没有数字只是意味着默认值是1。你觉得“打包通常正确”??也许你认为 struct.pack("s", foo)
和 "%s" % foo
是一样的?其实并不是;文档上说:“对于's'格式字符,计数被解释为字符串的大小,而不是像其他格式字符那样的重复计数;例如,'10s'表示一个10字节的字符串,而'10c'表示10个字符。对于打包,字符串会被截断或用空字节填充,以适应大小。”
@Brendan: -1。value
不是数组(不管那是什么);它显然是一个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"))
现在假设 value
是 u'\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)
这其实是一个普通的字符串格式,用来创建结构体格式。
先把它当作普通字符串来看(暂时不考虑struct
)……
"<ii%ds" % len(value)
比如说,如果这个值的可迭代对象的长度是4,那么这个字符串就会变成<ii4s
。接下来,这个字符串会被传递给struct.pack
,准备打包两个整数和一个长度为四个字节的字符串,这个字符串来自于value
这个可迭代对象。