Perl pack() и целочисленное переполнение

Я хочу упаковать различные результаты выражений с проверкой целочисленного переполнения в Perl (со знаком, без знака, с прямым порядком байтов и с прямым порядком байтов). Если я попробую:

$ perl -e 'use warnings; print pack("c", 200)' | hexdump -C

Я получил:

Character in 'c' format wrapped in pack at -e line 1.
00000000  c8                                                |.|
00000001

Есть ли способ проверить, произошло ли переполнение целых чисел в функции pack()? Или, может быть, заставить функцию потерпеть неудачу при переполнении? Если я проверю диапазон для каждого типа перед упаковкой (со знаком 1,2,4,8 байта, без знака 1,2,4,8), код кажется немного уродливым.

Благодарю.

2 ответа

Решение

Вы можете включить категорию предупреждений "pack" и сделать ее смертельной. Тогда переполнение вызовет исключение, которое может быть перехвачено. Например:

for my $val (127, 128) {
    print "$val -> ";
    if (eval {
        use warnings FATAL => qw(pack);
        pack("c", $val);
    }) {
        print "no overflow";
    } else {
        print "overflow ($@)";
    }
    print "\n";
}

Другая возможность заключается в использовании (предпочтительно локального) $SIG{__WARN__} обработчик и проверьте обработчик, если произошло предупреждение.

Фатализация предупреждений - самое простое решение, но вы можете написать свои собственные функции упаковки.

use Carp         qw( croak );
use Scalar::Util qw( looks_like_number );

sub pack_uint32_be {
   my ($n) = @_;
   croak "Not a number" unless looks_like_number($n);
   croak "Overflow"     unless 0 < $n && $n <= 2**32;
   return pack 'L>', $n;
}

$packed .= pack_uint32_be($x);
$packed .= pack_uint32_be($y);
Другие вопросы по тегам