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

时间:2009-11-24 14:21:55

标签: perl hex checksum

我正在迭代一组32位十六进制字符串(“DEADBEEF”,“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”,“44444444”和“44444444”。输出是:

  

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

等。

你可以看到前两个总结是正确的,然后它似乎饱和。我是否遗漏了有关Perl变量大小限制的内容?

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

string: 7800798C, value: 2013297036, checksum 7800798C
string: 44444444, value: 1145324612, checksum BC44BDD0
string: 44444444, value: 1145324612, checksum FFFFFFFF
string: 44444444, value: 1145324612, checksum FFFFFFFF
string: 78007980, value: 2013297024, checksum FFFFFFFF
string: 44444444, value: 1145324612, checksum FFFFFFFF

4 个答案:

答案 0 :(得分:6)

如果使用32位整数编译perl,则导致数字大于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 ...

使用bignum为更大的整数添加透明支持:

#!/usr/bin/perl

use strict; use warnings;
use bignum qw/hex/;

my $x = hex '0x7800798C';
my $chk;

for (1 .. 10) {
    $chk += $x;
    $chk &= 0xFFFFFFFF;
    printf("checksum: %08X\n", $chk);
}

验证输出符合您的期望:

checksum: 7800798C
checksum: F000F318
checksum: 68016CA4
checksum: E001E630
checksum: 58025FBC
checksum: D002D948
checksum: 480352D4
checksum: C003CC60
checksum: 380445EC
checksum: B004BF78

没有bignum,我得到:

checksum: 7800798C
checksum: F000F318
checksum: FFFFFFFF
checksum: FFFFFFFF
checksum: FFFFFFFF
...

答案 1 :(得分:6)

之前曾在Perl Monks询问过。

答案似乎是“use integer”。

请参阅Perl Monks和perldoc integer的原始答案。

$ perl -we 'use integer; printf("%08X\n",  0xFFFF_FFFF + 0xFFFF_FFFF)'

答案 2 :(得分:3)

你想要什么结果? &=将删除大于0xffffffff的任何数字位。将数字连续添加在一起只会获得越来越大的数字,然后使用&进行0xffffffff。在某些时候,我希望你会得到0xffffffff以外的东西,不是吗?但它永远不会更大!

制作校验和的更好方法可能是xor你的数字。

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);
}

这将使这些数字具有独特性。

答案 3 :(得分:3)

要展开Sinan's answer&=运算符和%X格式都会受到编译到Perl中的整数大小的影响。在这种情况下,两者的最大大小为4294967295或0xFFFFFFFF。

虽然您的变量可以包含大于此值的值,但在通过&=sprintf("%X")时,它们将被截断为此最大值。