Использует ли процедура 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 не использует системный десятичный разделитель.

Другие вопросы по тегам