Val过程是否使用DecimalSeparator?

问题描述 投票:6回答:1

StrToFloat使用格式设置的DecimalSeparator

似乎Val只接受包含.作为小数分隔符的字符串。

_ValExtVal调用)中的ASM代码看起来它不使用DecimalSeparator

我可以安全地依赖Val接受.作为小数分隔符的实数字符串的事实(?)吗?

delphi delphi-5
1个回答
8
投票

Val古老,低级,使用起来有点棘手。我不建议在用户代码中使用它。而是使用其他例程来扫描值,例如StrToFloat等。如果你使用StrToFloatTFormatSettings.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不使用系统定义的小数分隔符,只接受不变的小数分隔符,即'.'。 IMO,System.Val的文档在这里有点误导。

UPDATE

似乎我在代码的“单个部分”中使用了E而不是S。如果你传递一个Single,显然你也得到了正确的值,所以我猜编译器(它知道传递了什么)以某种方式将这些信息传递给内部例程。

查看CPU窗口,您可以看到,如果传入浮点类型,则调用System.@ValExt,它返回FPU堆栈顶部的值(ST(0))。编译器比添加适当的代码来存储该值(FSTP TBYTEFSTP QWORDFSTP DWORD分别用于ExtendedDoubleSingle)。

类似地,对于整数变量(最多32位),调用System.@ValLong,它在Integer中返回EAX,并且编译器添加用于以正确大小存储值的适当代码。对于64位整数,调用@ValInt64,它返回EDX:EAX中的值。

FWIW,它还表明Writeln不使用系统定义的小数分隔符。

© www.soinside.com 2019 - 2024. All rights reserved.