Linux Perl — преобразование шестнадцатеричного значения в десятичное

#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