Val 过程是否使用 DecimalSeparator?
Does the Val procedure use DecimalSeparator?
StrToFloat
使用格式设置的DecimalSeparator
。
似乎 Val
只接受包含 .
作为小数分隔符的字符串。
从 _ValExt
中的 ASM 代码(Val
调用)看来它没有使用 DecimalSeparator
。
我可以放心地相信 Val
接受以 .
作为小数点分隔符的实数字符串吗?
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
不使用系统定义的小数点分隔符,只接受不变的小数点分隔符,即'.'
。 IMO,System.Val
的文档在这里有点误导。
更新
似乎我在代码的 "single part" 中使用了 E
而不是 S
。显然,如果你传递 Single
,你也会得到正确的值,所以我猜编译器(知道传递了什么)以某种方式将此信息传递给内部例程。
查看CPUwindow,可以看到如果传入浮点类型,则调用System.@ValExt
,即returns FPU 堆栈顶部的值 (ST(0)
)。然后编译器添加适当的代码来存储该值(FSTP TBYTE
、FSTP QWORD
或 FSTP DWORD
分别对应 Extended
、Double
和 Single
.
类似地,对于整型变量(最多32位),调用System.@ValLong
,其中returns an Integer
in EAX
,和编译器添加了适当的代码来以正确的大小存储值。对于 64 位整数,调用 @ValInt64
,其中 returns 是 EDX:EAX
中的一个值。
FWIW,它还表明 Writeln
不使用系统定义的小数点分隔符。
StrToFloat
使用格式设置的DecimalSeparator
。
似乎 Val
只接受包含 .
作为小数分隔符的字符串。
从 _ValExt
中的 ASM 代码(Val
调用)看来它没有使用 DecimalSeparator
。
我可以放心地相信 Val
接受以 .
作为小数点分隔符的实数字符串吗?
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
不使用系统定义的小数点分隔符,只接受不变的小数点分隔符,即'.'
。 IMO,System.Val
的文档在这里有点误导。
更新
似乎我在代码的 "single part" 中使用了 E
而不是 S
。显然,如果你传递 Single
,你也会得到正确的值,所以我猜编译器(知道传递了什么)以某种方式将此信息传递给内部例程。
查看CPUwindow,可以看到如果传入浮点类型,则调用System.@ValExt
,即returns FPU 堆栈顶部的值 (ST(0)
)。然后编译器添加适当的代码来存储该值(FSTP TBYTE
、FSTP QWORD
或 FSTP DWORD
分别对应 Extended
、Double
和 Single
.
类似地,对于整型变量(最多32位),调用System.@ValLong
,其中returns an Integer
in EAX
,和编译器添加了适当的代码来以正确的大小存储值。对于 64 位整数,调用 @ValInt64
,其中 returns 是 EDX:EAX
中的一个值。
FWIW,它还表明 Writeln
不使用系统定义的小数点分隔符。