Contents of this directory is archived and no longer updated.

Примечание: данный пост перепечатан в связи с закрытием бложиков на spaces.live.com, как имеющий какую-то ценность для автора и/или читателей.


Как известно, PowerShell позволяет очень просто конвертировать hexadecimal значения в decimal. Достаточно в консоли набрать 0xhex_значение. Вот несколько примеров:

[C:\] 0xFF
255
[C:\] 0x12345
74565
[C:\] 0xDead
57005

Кажется тут всё очень просто и говорить как бы не о чем даже. Однако при работе с относительно большими величинами нужно учитывать тип вводимых данных. К типам данных относятся следующие типы:

  • Int32 - signed integer (знаковое целое, 32-х разрядное). Диапазон чисел от -2147483648 до 2147483647
  • UInt32 - unsigned integer (беззнаковое целое, 32-х разрядное). Диапазон чисел от 0 до 4294967295
  • Int64 - signed integer (знаковое целое, 64-х разрядное). Диапазон чисел от -9223372036854775808 до 9223372036854775807
  • UInt64 - unsigned integer (беззнаковое целое, 64-х разрядное). Диапазон чисел от 0 до 1,84467440737096E+19

и много других типов (Decimal, Single, Double, etc). В контексте hexadecimal чисел нас будут интересовать только эти 4 типа представления чисел. К чему я это? А к тому, что при конвертировании определённых чисел из hex в decimal вы можете получить не совсем ожидаемый результат. Например:

[C:\] 0x7FFFFFFF
2147483647

и если мы прибавим единичку к этому выражению, то получим hex значение 0x80000000 и которое должно равняться 2147483648 в десятичном выражении. Посмотрим, что скажет нам PowerShell:

[C:\] 0x80000000
-2147483648

откуда появился знак минуса? А появился он очень просто. Я специально выше указал диапазоны значений для каждого типа данных. Дело в том, что 0x7FFFFFFF является самым большим положительным числом для типа Int32 и 0x80000000 в десятичной форме будет самым большим отрицательным числом для Int32. Диапазон отрицательных чисел для Int32 находится между -2147483648 (0x8000000) и -1 (0xFFFFFFFF). По умолчанию PowerShell старается присвоить число к типу Int32 или Int64. Как в этом можно убедиться? А очень просто:

[C:\] (0xDead).gettype().fullname
System.Int32
[C:\] (4294967296).gettype().fullname
System.Int64

Здесь видно, что PowerShell число 0xDead присвоил к типу Int32, а число 4294967296 присвоил к типу Int64. И если мы работаем только с арифметикой (только положительными числами), то при использовании типов Int32/Int64 мы будем получать весьма неожиданные результаты в виде отрицательных чисел. Поэтому нам нужен механизм, который бы подсказал PowerShell'у тот тип данных, который нам нужен. Это делается следующим образом - [тип_данных]данные:

[C:\] [Uint64]0x123ABC
1194684
[C:\] ([uint64]0x123ABC).gettype().fullname
System.UInt64

UInt32/UInt64 не содержит отрицательных чисел в десятичном представлении, поэтому при работе только с положительными числами нужно использовать тип UInt32/UInt64, который избавит нас от проблем с появлением отрицательных чисел:

[C:\] [UInt32]0x80000000
Cannot convert value "-2147483648" to type "System.UInt32". Error: "Value was either too large or too small for a UInt3
2."
At line:1 char:9
+ [UInt32] <<<< 0x80000000

Как же так? Мы явно указали, что следует использовать тип UInt32!!! И вот я вас подвёл к тому, что хотел сказать - на самом деле PowerShell всю процедуру преобразования чисел в типы данных выполняет следующим образом:

  1. сперва пытается преобразовать число в Int32;
  2. Если удалось преобразовать в Int32, то уже после этого переводит число в тот тип, который мы указали явно.
  3. Если не удалось преобразовать в Int32, то делается попытка преобразовать его в Int64;
  4. Если удалось преобразовать в Int64, то после этого переводит в тот тип, который мы указали явно;
  5. Если не удалось преобразовать число в Int64, то делается попытка преобразовать его в другие типы чисел (например, Double, если число не является целым).

Согласно этой последовательности действий PowerShell сначала преобразовал число 0x8000000 в Int32 и ему это удалось (получил -2147483648), после чего PowerShell перешёл к шагу 2 и попытался преобразовать число -2147483648 в UInt32. Но, как я уже сказал, UInt32/UInt64 не могут содержать отрицательных чисел, поэтому мы и получили ошибку. Это определённый недостаток, что PowerShell сначала делает своё внутреннее преобразование числа, а только потом пытается преобразовать к тому типу, который мы указываем явно. Однако PowerShell имеет механизм (большое спасибо разработчикам PowerShell за очень быструю реакцию в решении этого вопроса), который переопределяет порядок преобразований типов данных. Для того, чтобы PowerShell чётко следовал нашим инструкциям и сразу преобразовывал число в указанный явно тип данных нужно данное hexadecimal число включить в одинарные кавычки.

[C:\] [UInt32]'0x80000000'
2147483648

вот теперь мы получаем ожидаемый результат. Исходя из всего выше сказанного при работе с hexadecimal числами следует взять за правило явное указание типа используемых данных и включение hex числа в одинарные кавычки, как это показано на последнем примере.

Кстати говоря, использование кавычек (как одинарных, так и двойных) имеет достаточно много интересных и полезных особенностей. Для вводного курса по кавычкам советую почитать в блоге Василия Гусева:

Всякие загогулинки

Иногда кавычки имеют значение ;)

Хорошо всё то, что хорошо заканчивается :-)


Share this article:

Comments:

Comments are closed.