如何在Perl中对大的十六进制值求和?

如何在Perl中对大的十六进制值求和?,perl,hex,checksum,Perl,Hex,Checksum,我迭代一组32位十六进制字符串(“死牛肉”、“12345678”等),并尝试将它们相加以形成32位校验和。假设变量$temp在下面的示例中加载了一些十六进制字符串 my $temp; my $checksum; for (...) { #assume $temp is loaded with a new hex string here my $tempNum = hex ($temp); $checksum += $tempNum; $checksum &

我迭代一组32位十六进制字符串(“死牛肉”、“12345678”等),并尝试将它们相加以形成32位校验和。假设变量
$temp
在下面的示例中加载了一些十六进制字符串

my $temp;
my $checksum;

for (...)
{
    #assume $temp is loaded with a new hex string here
    my $tempNum = hex ($temp);
    $checksum += $tempNum;
    $checksum &= 0xFFFFFFFF;
    print printf("checksum: %08X",$checksum);
}
前几个值是“7800798C”、“4444”和“4444”。输出为:

校验和:7800798C
校验和: BC44BDD0
校验和:FFFFFFFF
校验和:FFFFFFFF

等等

正如你所看到的,前两个总和是正确的,然后它似乎饱和了。关于Perl变量的大小限制,我遗漏了什么吗

编辑:这是脚本的实际输出(字符串是十六进制字符串,值是该字符串的十进制转换,校验和是结果输出):

字符串:7800798C,值:2013297036,校验和7800798C 字符串:4444,值:1145324612,校验和BC44BDD0 字符串:4444,值:1145324612,校验和FFFFFF 字符串:4444,值:1145324612,校验和FFFFFF 字符串:78007980,值:2013297024,校验和FFFF 字符串:4444,值:1145324612,校验和FFFFFF
如果您的
perl
是用32位整数编译的,那么导致数字大于
0xffffffff
的整数操作将导致问题。例如:

my $x = hex '0x1234567890';
my $y = hex '0x1234567890';

print $x + $y,  "\n";
您将获得:

Integer overflow in hexadecimal number at ... Hexadecimal number > 0xffffffff non-portable at ... 验证输出是否符合您的期望:

checksum: 7800798C checksum: F000F318 checksum: 68016CA4 checksum: E001E630 checksum: 58025FBC checksum: D002D948 checksum: 480352D4 checksum: C003CC60 checksum: 380445EC checksum: B004BF78
你想要什么结果?
&=
将删除大于
0xffffffff
的任何数字位。不断地把数字加在一起只会得到一个越来越大的数字,然后用
0xffffff
编辑这个数字。在某个时刻,我希望你得到的不是
0xffffffff
,不是吗?但它永远不会更大

也许一个更好的校验和方法是将数字一起进行异或

my $temp;
my $checksum;

for (...)
{
    #assume $temp is loaded with a new hex string here
    my $tempNum = hex ($temp);
    $checksum ^= $tempNum;
    print printf("checksum: %08X",$checksum);
}
这将使这些数字成为独一无二的。

要进一步展开,编译成Perl的整数的大小会影响
&=
运算符和
%X
格式。在本例中,的最大大小为4294967295或0xFFFFFF

虽然您的变量可以包含大于此值的值,但当通过
&=
sprintf(“%X”)
时,它们将被截断到此最大值,这是以前在中提出的问题

答案似乎是“
使用整数”

请参阅Perl Monks和的原始答案


我觉得你的回答有点神秘。如果他继续添加数字,而不是&=它们,他将得到一个浮点数。如果我最终得到一个整数,其中低32位被设置,并且&=它与0xFFFFFF,我肯定会得到0xFFFFFF,但仅用于该加法。将任何其他数字添加到此总和将产生唯一值。换句话说,在这个求和中,我永远不会得到一个无限期的0xFFFFFF,但你不会得到一个整数。在32位系统上,加法会产生一个浮点(NV),然后当您尝试用整数对其进行位运算时,Perl不知道该做什么,并决定整数结果为0xFFFFFF。这不是一个完美的选择,但这是一个选择
use integer
通过拒绝提升到float来解决问题,因此integer+integer会给出integer(必要时进行包装)。看起来很奇怪,您是否可以在该printf中打印$tempNum?此代码不会生成校验和。甚至在Perl中也没有@bzlm:我知道:)这只是校验和操作的一部分,其余部分似乎没有问题,所以我没有包括在内。你能发布一个简短的脚本,实际编译和运行吗?为什么(…)
?什么是
printf(…)?
ok,这很有意义。假设我想执行所有这些加法,然后将32个最低有效位打印到一个新变量中——我将如何实现这一点?我明白我不能像我最初打算的那样使用&=或sprintf。@Sinan:我必须回滚您的编辑:-M比“use”更不为人所知,而且integer的perldoc链接很难被注意到-看起来像是语法高亮显示。-如果您一直对人隐藏它,M将不为人所知。:) checksum: 7800798C checksum: F000F318 checksum: 68016CA4 checksum: E001E630 checksum: 58025FBC checksum: D002D948 checksum: 480352D4 checksum: C003CC60 checksum: 380445EC checksum: B004BF78 checksum: 7800798C checksum: F000F318 checksum: FFFFFFFF checksum: FFFFFFFF checksum: FFFFFFFF ...
my $temp;
my $checksum;

for (...)
{
    #assume $temp is loaded with a new hex string here
    my $tempNum = hex ($temp);
    $checksum ^= $tempNum;
    print printf("checksum: %08X",$checksum);
}
$ perl -we 'use integer; printf("%08X\n",  0xFFFF_FFFF + 0xFFFF_FFFF)'