В delphi есть UIntToStr, чтобы вы могли отображать значения UINT64, но где же StrToUInt, чтобы позволить пользователю вводить 64-битные значения без знака? - PullRequest
10 голосов
/ 21 мая 2011

Я хочу преобразовать большое 64-битное значение из десятичной или шестнадцатеричной строки в 64-битный тип данных UINT64. Существует UIntToStr, чтобы помочь преобразовать UINT64 в строку, но нет способа преобразовать 64-разрядное целое число в значение без знака, как строку. Это означает, что целочисленные значения больше 2 ** 63 не могут быть представлены в десятичном или шестнадцатеричном виде с использованием RTL. Обычно это не имеет большого значения, но может случиться так, что пользователю потребуется ввести значение в виде целого числа без знака, которое должно быть сохранено в реестре как 64-разрядное целое число без знака.

procedure HandleLargeHexValue;

var
 x:UINT64;
begin

  x := $FFFFFFFFFFFFFFFE;

  try
  x := StrToInt('$FFFFFFFFFFFFFFFF'); // range error.
  except
    x := $FFFFFFFFFFFFFFFD;
  end;

  Caption := UintToStr(x);

end;

Обновление Val сейчас работает отлично в Delphi XE4 и выше. В XE3 и ниже Val ('$ FFFFFFFFFFFFFFFF') работает, но не Val ('9223372036854775899'). Как указывает Роланд ниже в Quality Central 108740: System.Val имел проблемы с большими значениями UInt64 в десятичном формате до Delphi XE4.

Ответы [ 3 ]

6 голосов
/ 21 мая 2011

ОБНОВЛЕНИЕ: В XE4 и позже исправлена ​​ошибка RTL. Этот хак полезен только в Delphi XE3 или старше

Ну, если его там нет, я думаю, я всегда смогу написать это.

(я тоже написал для этого неплохой юнит-тест, но он слишком большой, чтобы публиковать здесь)

unit UIntUtils;

{ A missing RTL function written by Warren Postma. }

interface
  function TryStrToUINT64(StrValue:String; var uValue:UInt64 ):Boolean;
  function StrToUINT64(Value:String):UInt64;

implementation

uses SysUtils,Character;

{$R-}

function TryStrToUINT64(StrValue:String; var uValue:UInt64 ):Boolean;
var
  Start,Base,Digit:Integer;
  n:Integer;
  Nextvalue:UInt64;
begin
  result := false;
  Base := 10;
  Start := 1;
  StrValue := Trim(UpperCase(StrValue));
  if StrValue='' then
    exit;
  if StrValue[1]='-' then
    exit;
  if StrValue[1]='$' then
  begin
    Base := 16;
    Start := 2;
    if Length(StrValue)>17 then // $+16 hex digits = max hex length.
        exit;
  end;
  uValue := 0;
  for n := Start to Length(StrValue) do
  begin
      if Character.IsDigit(StrValue[n]) then
          Digit := Ord(StrValue[n])-Ord('0')
      else if  (Base=16) and (StrValue[n] >= 'A') and (StrValue[n] <= 'F') then
          Digit := (Ord(StrValue[n])-Ord('A'))+10
      else
          exit;// invalid digit.

      Nextvalue := (uValue*base)+digit;
      if (Nextvalue<uValue) then
          exit;
      uValue := Nextvalue;
  end;
  result := true; // success.
end;

function StrToUINT64(Value:String):UInt64;
begin
  if not TryStrToUINT64(Value,result) then
    raise EConvertError.Create('Invalid uint64 value');

end;

end.
4 голосов
/ 05 ноября 2012

Я должен не согласиться с тем, что Вэл решает эту проблему.Val работает только для больших значений UInt64, когда они написаны в шестнадцатеричном формате.Когда они записаны в десятичном виде, последний символ удаляется из строки, а полученное значение неверно.

См. Quality Central 108740: System.Val имеет проблемы с большими значениями UInt64 РЕДАКТИРОВАТЬ:Похоже, эта проблема должна быть решена в XE4.Не могу проверить это.

3 голосов
/ 22 мая 2011

При значении UINT64 приведенный ниже фрагмент кода дает ожидаемый ответ в Delphi 2010, но только в том случае, если входные значения представлены в шестнадцатеричном формате

  stringValue := '$FFFFFFFFFFFFFFFF';
  val( stringValue, value, code );

  ShowMessage( UIntToStr( value ));

Я бы просто обернул val в удобную функцию, и все готово.

Теперь не стесняйся сжечь меня. Я пропустил цифру в моих тестах? : D

...