Val 过程是否使用十进制分隔符?



StrToFloat使用格式设置的DecimalSeparator

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

_ValExt(Val调用)中的ASM代码来看,它似乎不使用DecimalSeparator

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

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不使用系统定义的小数分隔符,而只接受不变的小数分隔符,即'.'.IMOSystem.Val的文档在这里有点误导。

更新

似乎我在代码的"单个部分"中使用了E而不是S。显然,如果您传递Single,您也会获得正确的值,因此我猜编译器(知道传递了什么)以某种方式将此信息传递给内部例程。

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

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

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

最新更新