Is it OK to use DecimalSeparator to force Floattostr/Strtofloat functions to use a decimal point

前端 未结 5 1413
天涯浪人
天涯浪人 2021-01-02 08:29

Currently, I\'m setting DecimalSeparator to a \'.\' in each procedure which uses these functions.

It would be much easier to set this globally at the start of the pr

相关标签:
5条回答
  • 2021-01-02 08:58

    It's OK if you have no alternative. Prefer the versions of those functions that accept a TFormatSettings parameter, if your Delphi version is recent enough, so that you don't interfere with any other code that relies on that global variable for locale-aware behavior.

    FloatToStr and StrToFloat are locale-sensitive functions. If you need to convert your floating-point value to a string to persist it somewhere that a program will read later (such as to a file, the registry, or a network socket), then you should use the locale-independent functions Str and Val for your conversions instead. They always use . for the decimal separator, regardless of the DecimalSeparator variable or other environmental settings.

    0 讨论(0)
  • 2021-01-02 09:00

    You could patch every string before and after calling a RTL function with some ForceLocalSeparator() and ForceDotSeparator() functions.

    // before a RTL call
    Function ForceLocalSeparator(Const StrValue: String): String;
    Var
      SepPos: Integer;
    Begin
      Result := StrValue;
      If DecimalSeparator <> '.' Then
        Begin
          SepPos := Pos( '.', Result );
          If SepPos > 0 Then Result[SepPos] := DecimalSeparator;
        End;
    End;
    
    // after a RTL call
    Function ForceDotSeparator(Const StrValue: String): String;
    Var
      SepPos: Integer;
    Begin
      Result := StrValue;
      If DecimalSeparator <> '.' Then
        Begin
          SepPos := Pos( DecimalSeparator, Result );
          If SepPos > 0 Then Result[SepPos] := '.';
        End;
    End;
    
    0 讨论(0)
  • 2021-01-02 09:08

    Yes, the DecimalSeparator global variable might be changed by the RTL during runtime, which caused a lot of headache for me a few years ago before I realised this.

    The thing is that DecimalSeparator is updated by the RTL when the Windows decimal separator is changed, for instance, using the Control Panel. This might seem like a rather small problem. Indeed, how often does the end user change the system's decimal separator?

    The big issue is that the DecimalSeparator variable is updated (according to the system setting) every time you switch user (in Windows). That came as a surprise to me. That is, if your system setting uses a comma (',') as the decimal separator, and you set DecimalSeparator := '.' at application startup, then DecimalSeparator will revert to a comma if you switch user (and you'll notice that when you switch back).

    You can tell the RTL not to update the decimal separator by

    Application.UpdateFormatSettings := false;
    

    At any rate, there are better alternatives to DecimalSeparator, as discussed in other answers and comments.

    0 讨论(0)
  • 2021-01-02 09:11

    I am/was under the assumption that the global DecimalSeperator variable would not be touched by the RTL. If not, then all these routines have an optional parameter FormatSettings which you could use. Globaly declare a TFormatSettings variable and use it for each occurance of these routines.

    A small benefit of it could be that the routines are thread-safe when you specify your own format settings.

    0 讨论(0)
  • 2021-01-02 09:22

    To be on the safe side, i would use TFormatSettings, this has two advantages:

    1. The formatting is thread safe, other code/libraries cannot influence your function.
    2. You do not influence other code, which possibly rely upon certain settings.

    Here a possible implementation:

    function FloatToStrWithDecimalPoint(const Value: Extended; const Format: String = '0.###'): String;
    var
      myFormatSettings: TFormatSettings;
    begin
      GetLocaleFormatSettings(GetThreadLocale, myFormatSettings);
      myFormatSettings.DecimalSeparator := '.';
      Result := FormatFloat(Format, Value, myFormatSettings);
    end;
    
    0 讨论(0)
提交回复
热议问题