Использует ли процедура Val DecimalSeparator?
StrToFloat
использует DecimalSeparator
настроек формата.
Кажется, что Val
принимает только те строки, которые содержат .
в качестве десятичного разделителя.
Из кода ASM в _ValExt
(который Val
звонки) похоже не пользуется DecimalSeparator
,
Могу ли я смело полагаться на тот факт (?), Что Val
принимает строки действительных чисел с .
как десятичный разделитель?
1 ответ
Val
древний, низкий уровень и немного сложный в использовании. Я бы не рекомендовал использовать его в коде пользователя. Скорее используйте другие процедуры для сканирования значений, таких как StrToFloat
и т. д. Если вы используете StrToFloat
с TFormatSettings.Invariant
, вы можете быть уверены, что вы получите точку ('.'
) в качестве десятичного разделителя.
Взгляните на следующий фрагмент тестового кода. В моей немецкой системе десятичный разделитель - запятая. Поэтому я попробовал следующее:
procedure Test;
var
E: Extended;
S: Single;
I: Integer;
Code: Integer;
begin
Val('1.234', E, Code);
if Code = 0 then
Writeln('1.234 Extended: ', E)
else
Writeln('1.234 Extended: Error, code = ', Code);
Val('1,234', E, Code);
if Code = 0 then
Writeln('1,234 Extended: ', E)
else
Writeln('1,234 Extended: Error, code = ', Code);
Val('1.234', S, Code);
if Code = 0 then
Writeln('1.234 Single: ', S)
else
Writeln('1.234 Single: Error, code = ', Code);
Val('1234', I, Code);
if Code = 0 then
Writeln('Integer: ', I)
else
Writeln('Integer: Error, code = ', Code);
end;
Выход:
1.234 Extended: 1.23400000000000E+0000
1,234 Extended: Error, code = 2
1.234 Single: 1.23399996757507E+0000
Integer: 1234
Это ясно показывает, что Val
не использует системный десятичный разделитель, а принимает только инвариантный десятичный разделитель, т.е. '.'
, Документы для System.Val
немного вводит в заблуждение здесь, ИМО.
ОБНОВИТЬ
Кажется я использовал E
вместо S
в "единой части" кода. Видимо, вы также получите правильное значение, если вы передаете Single
Я думаю, что компилятор (который знает, что передается) каким-то образом передает эту информацию во внутреннюю процедуру.
Глядя в окно ЦП, вы можете видеть, что если передается тип с плавающей запятой, System.@ValExt
вызывается, который возвращает значение в верхней части стека FPU ( ST(0)
). Компилятор добавляет соответствующий код для хранения этого значения ( FSTP TBYTE
, FSTP QWORD
или же FSTP DWORD
за Extended
, Double
а также Single
соответственно).
Точно так же для целочисленных переменных (до 32 бит), System.@ValLong
называется, который возвращает Integer
в EAX
и соответствующий код для хранения значения в нужном размере добавляется компилятором. Для 64-битных целых чисел @ValInt64
называется, который возвращает значение в EDX:EAX
,
FWIW, это также показывает, что Writeln
не использует системный десятичный разделитель.