Val
is ancient, low level and a bit tricky to use. I would not recommend using it in user code. Rather use other routines to scan values, like StrToFloat
, etc. If you use StrToFloat
with TFormatSettings.Invariant
, you can be sure that you get the dot ('.'
) as decimal separator.
Take a look at the following piece of test code. On my German system, the decimal separator is a comma. So I tried the following:
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;
The output is:
1.234 Extended: 1.23400000000000E+0000
1,234 Extended: Error, code = 2
1.234 Single: 1.23399996757507E+0000
Integer: 1234
This clearly demonstrates that Val
does not use the system-defined decimal separator, and only accepts the invariant decimal separator, i.e. '.'
. The docs for System.Val
are a little misleading here, IMO.
UPDATE
Seems I used E
instead of S
in the "single part" of the code. Apparently you also get the correct value if you pass a Single
, so I guess the compiler (which knows what gets passed) somehow passes this information to the internal routine.
Looking at the CPU window, you can see that if a floating point type is passed in, System.@ValExt
is called, which returns the value on the top of the FPU stack (ST(0)
). The compiler than adds the appropriate code to store that value (FSTP TBYTE
, FSTP QWORD
or FSTP DWORD
for Extended
, Double
and Single
, respectively).
Similarly, for integral variables (up to 32 bit), System.@ValLong
is called, which returns an Integer
in EAX
, and appropriate code to store the value in the right size is added by the compiler. For 64 bit integers, @ValInt64
is called, which returns a value in EDX:EAX
.
FWIW, it also shows that Writeln
doesn't use the system-defined decimal separator.
StrToFloat
and define whatever format you need? That's what it's for, and it's immensely more readable and maintainable. – SaxonVal
provides a critical optimization I'd avoid it, personally, at least for production code. – SaxonDecimalSeparator
; setDecimalSeparator
to'.'
; callStrToFloat
and restore theDecimalSeparator
. not nice IMO, and not thread safe. In my case I know that the input string always contains '.' as separators. – UraniniteVal
acts the same for all version? the fact that there are better options likeTFormatSettings
does not changes the question I asked:Does the Val procedure use DecimalSeparator?
– Uraninite