#linux #perl #hex #decimal
#linux #perl #шестнадцатеричное #десятичное
Вопрос:
Я разрабатываю скрипт, который преобразует собранные шестнадцатеричные (я не знаю их битовый формат) значения в десятичные значения.
Одним из примеров является шестнадцатеричное значение: fef306da Если я его конвертирую, я получаю 4277339866.
Веб-сайт, на котором я нашел ожидаемое значение (десятичное из дополнения signed 2 :): https://www.rapidtables.com/convert/number/hex-to-decimal.html
У вас, ребята, есть решение, как я могу преобразовать шестнадцатеричное значение fef306da в десятичное -17627430. Примечание: я получаю неправильное преобразование значений при преобразовании шестнадцатеричных значений, которые имеют (-) отрицательный знак при десятичном.
Спасибо всем!
Ответ №1:
Посмотрите на pack и используйте модификаторы для значений без знака и знака.
my $hex_value = "fef306da";
my $output_num = unpack('l', pack('L', hex($hex_value)));
print $output_num; ## -17627430
Выполните проверку каждого шестнадцатеричного значения, чтобы определить, является ли оно 16-битным или 32-битным значением.
Затем используйте правильный модификатор с pack для длинных или коротких значений.
Комментарии:
1. Большое спасибо за объяснение! Вы оба спасли мне жизнь. Хотел бы я знать это раньше. Просто так получилось, что я впервые сталкиваюсь с другим преобразованием шестнадцатеричного числа в десятичное.. ^_^ И, кстати.. Ваш $output_num должен быть вашим $num? XD Еще раз спасибо!
2. разобрал — рад, что это вам помогло. pack — ценный инструмент.
Ответ №2:
кажется, вы ожидаете, что ваше десятичное число будет 32-битным целым числом со знаком, но HEX ($ n) возвращает 64-битное, поэтому вы можете попробовать его перепаковать
perl -e 'print unpack "l", pack "L", hex( "fef306da" )'
Комментарии:
1. Большое спасибо, Майк! Я ценю это! : D
Ответ №3:
Если вас интересует двоичное преобразование, проверьте следующий код ( fef306da
32-битное число)
use strict;
use warnings;
use feature 'say';
my $input = 'fef306da';
my $hex = hex($input);
my $dec;
if( $hex amp; 0x80000000 ) {
$dec = -1 * ((~$hex amp; 0x7fffffff) 1);
} else {
$dec = $data;
}
say $dec;
Вывод
-17627430
Совет: дополнение к двум
Комментарии:
1. Совет: используйте лучшие имена переменных.
$hex
не содержит ничего шестнадцатеричного. Кроме того,-1 * ((~$num amp; 0x7fffffff) 1)
может быть упрощен до0x1_0000_0000 - $num
2. @ikegami — ну, я согласен, что так и должно быть
$raw
, но в качестве производной от шестнадцатеричного значения было бы легче понять людям, которые не имеют опыта в двоичной математике. Мне нужен отпечаток в моем мозгу0x1_0000_0000-$num
в качестве альтернативы — теперь, глядя на двоичную операцию , становится очень очевидным, почему-то мне не приходило в голову, почему присутствует 1 .
Ответ №4:
Вы могли бы использовать pack
my $hex = "fef306da";
my $num = hex($hex);
$num = unpack("l", pack("L", $num));
say $num; # -17627430
или
my $hex = "fef306da";
$hex = substr("00000000$hex", -8); # Pad to 8 chars
my $num = unpack("l>", pack("H8", $hex));
say $num; # -17627430
Но простая арифметика подойдет.
my $hex = "fef306da";
my $num = hex($hex);
$num -= 0x1_0000_0000 if $num >= 0x8000_0000;
say $num; # -17627430