Perl-функция для отрицательных целых чисел с использованием дополнения 2 - PullRequest
1 голос
/ 07 сентября 2010

Я пытаюсь преобразовать AD maxpwdAge (64-разрядное целое число) в количество дней.

По данным Microsoft :

Использует метод Get интерфейса IAD для получения значения атрибута maxPwdAge домена (строка 5).

Обратите внимание, что мы используем ключевое слово Set в VBScript для инициализации переменной с именем objMaxPwdAge - переменной, используемой для хранения значения, возвращаемого Get. Почему это?

Когда вы выбираете 64-битное большое целое число, ADSI не возвращает одно гигантское скалярное значение. Вместо этого ADSI автоматически возвращает объект IADsLargeInteger. Для вычисления значения большого целого числа вы используете свойства HighPart и LowPart интерфейса IADsLargeInteger. Как вы уже догадались, HighPart получает старшие 32 бита, а LowPart получает младшие 32 бита. Следующая формула используется для преобразования HighPart и LowPart в значение большого целого числа.

Существующий код в VBScript с той же страницы:

Const ONE_HUNDRED_NANOSECOND = .000000100   ' .000000100 is equal to 10^-7
Const SECONDS_IN_DAY = 86400

Set objDomain = GetObject("LDAP://DC=fabrikam,DC=com")     ' LINE 4
Set objMaxPwdAge = objDomain.Get("maxPwdAge")              ' LINE 5

If objMaxPwdAge.LowPart = 0 Then
  WScript.Echo "The Maximum Password Age is set to 0 in the " & _
               "domain. Therefore, the password does not expire."
  WScript.Quit
Else
  dblMaxPwdNano = Abs(objMaxPwdAge.HighPart * 2^32 + objMaxPwdAge.LowPart)
  dblMaxPwdSecs = dblMaxPwdNano * ONE_HUNDRED_NANOSECOND   ' LINE 13
  dblMaxPwdDays = Int(dblMaxPwdSecs / SECONDS_IN_DAY)      ' LINE 14
  WScript.Echo "Maximum password age: " & dblMaxPwdDays & " days"
End If

Как я могу сделать это в Perl?

Ответы [ 2 ]

1 голос
/ 07 сентября 2010

Endianness может вступить в это, но вы можете сказать

#!/usr/bin/perl

use strict;
use warnings;

my $num = -37_108_517_437_440;

my $binary = sprintf "%064b", $num;

my ($high, $low) = $binary =~ /(.{32})(.{32})/;

$high = oct "0b$high";
$low  = oct "0b$low";

my $together = unpack "q", pack "LL", $low, $high;

print "num $num, low $low, high $high, together $together\n";
0 голосов
/ 08 сентября 2010

Я что-то упустил? Насколько я могу судить по вашему вопросу, ваша проблема не имеет ничего общего с дополнением 2. Насколько я могу сказать, все, что вам нужно / нужно сделать, это

use Math::BigInt;

use constant MAXPWDAGE_UNIT_PER_SEC => (
      1000 # milliseconds
    * 1000 # microseconds
    * 10   # 100 nanoseconds
);

use constant SECS_PER_DAY => (
      24 # hours
    * 60 # minutes
    * 60 # seconds
);

my $maxpwdage_full = ( Math::BigInt->new( $maxpwdage_highpart ) << 32 ) + $maxpwdage_lowpart;

my $days = $maxpwdage_full / MAXPWDAGE_UNIT_PER_SEC / SECS_PER_DAY;

Обратите внимание, что я намеренно использую 2 отдельные константы и делю их по порядку, потому что это делает делители меньше диапазона 32-битного целого числа. Если вы хотите написать это по-другому и хотите, чтобы он работал корректно на 32-битных perls, вам придется помнить все проблемы точности.

...