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