Theres UIntToStr в delphi позволяет отображать значения UINT64, но где StrToUInt позволяет пользователю вводить 64-битные значения без знака?

Я хочу преобразовать большое 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'). Как указывает Roeland ниже в Quality Central 108740: System.Val имел проблемы с большими значениями UInt64 в десятичном значении до Delphi XE4.

Ответ 1

UPDATE: в XE4 и позже исправлена ​​ошибка RTL. Этот взлом полезен только в Delphi XE3 или старше

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

(для этого я написал довольно хороший unit test, но его слишком большой для публикации здесь)

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.

Ответ 2

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

См. Quality Central 108740: System.Val имеет проблемы с большими значениями UInt64 EDIT: Кажется, что этот вопрос должен быть разрешен в XE4. Не удается проверить это.

Ответ 3

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

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

  ShowMessage( UIntToStr( value ));

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

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