如何在不实际拆包的情况下获得 Perl 中打包项目的数量?
Posted
技术标签:
【中文标题】如何在不实际拆包的情况下获得 Perl 中打包项目的数量?【英文标题】:How can I get the number of pack`ed items in Perl without actually unpacking? 【发布时间】:2010-09-30 20:59:13 【问题描述】:我有一个pack
ed 值的字符串,这些值是使用以下内容按顺序创建的:
while (...)
...
$packed .= pack( 'L', $val );
在另一个程序中,在我加载$packed
之后,我想知道实际打包了多少个值。 unpack
ing 之后我知道该怎么做:
my @vals = unpack( 'L*', $packed );
print scalar(@vals);
但这真的有必要吗?如果我只关心值的数量,我可以做得更好,跳过unpack
ing吗?
【问题讨论】:
关于打包,您应该将值存储在数组中 (push @data, $val
) 并将结果打包一次 ($packed = pack('L*', @data)
)。这将减少字符串分配的数量。
【参考方案1】:
既然您知道打包值的大小(L
是一个无符号的 32 位 int,或 4 个字节),只需将长度除以大小即可:
my $count = length($packed) / 4;
如果你不想硬编码大小,你也可以打包一个样本值来计算它。 (请注意,Perl 的编译时常量折叠不适用于 pack
,至少不适用于 5.10.1,因此您只想进行一次计算。)
my $size = length(pack('L', 0));
...
my $count = length($packed) / $size;
【讨论】:
@cjm 你能解释一下你的评论(Note that ...)
吗?我没听懂。
@David:Perl 解释器不会发现length(pack('L', 0))
是常量,所以每次找到时都会解释这个表达式。无论如何,您可以使用use constant LLength => length(pack("L", 0));
,perl 会为您插入它作为常量。
@David B,当 Perl 编译你的脚本时,它会执行constant folding。但是,从 5.10.1 开始,它无法识别 pack
(带有常量参数)可以在编译时进行评估,因此它无法将 length(pack('L', 0))
转换为 4
;每次执行该行代码时,它都必须创建打包字符串。这并不重要,除非您多次评估该表达式。
@cjm & Hynek -Pichi- Vychodil:谢谢大家,学习新东西总是很好。
FWIW,打包和解包不容易折叠起来,主要是因为p
模板。现在将它与文字字符串常量一起使用就可以了,因为表示常量的标量将被 optree 直接引用,并保留它。如果要折叠该常量并且在某些代码(例如unpack('p<', pack('p<', 'foo'))
)的行为中使用它的打包/解包,则会发生变化。这需要要么是一个非常聪明的优化,要么违反现有代码可能对文字字符串常量的生命周期做出的一些假设。【参考方案2】:
由于L
只是一组 32 位值,您可以简单地计算字节数并除以 4。
【讨论】:
【参考方案3】:use constant LLength => length(pack("L", 0));
...
print length($packed)/LLength;
检查LLength
是否真的是常数:
$ perl -MO=Deparse,-d -e'use constant L => length(pack("L", 0));print L, "\n";'
sub L () 4
use constant ("L", length pack("L", 0));
print 4, "\n";
-e syntax OK
【讨论】:
L
明确定义为 32 位整数,因此不需要此检查。这与原生 long 的 L!
不同。
@dolmen:你不知道。此检查检查 LLength
是否会作为常量放置在那里,或者会被评估为函数调用。它没有 L
、L!
或任何其他类型的任何内容。这是性能问题!以上是关于如何在不实际拆包的情况下获得 Perl 中打包项目的数量?的主要内容,如果未能解决你的问题,请参考以下文章
在 perl 中如何在不使用 XS 的情况下写入调用者的变量?