Erfahrungsbericht/ Bug FormatSettings.DecimalSeparator

Für Fehler in Lazarus, um diese von anderen verifizieren zu lassen.
Antworten
Benutzeravatar
corpsman
Lazarusforum e. V.
Beiträge: 1496
Registriert: Sa 28. Feb 2009, 08:54
OS, Lazarus, FPC: Linux Mint Mate, Lazarus GIT Head, FPC 3.0
CPU-Target: 64Bit
Wohnort: Stuttgart
Kontaktdaten:

Erfahrungsbericht/ Bug FormatSettings.DecimalSeparator

Beitrag von corpsman »

Servus mit einander,

hin und wieder habe ich böse Abstürze mit meinem Programm unter Windows 7.

Nach nun einer viel zu langen Zeit habe ich endlich eine Sequenz gefunden, mit derer ich den Bug nachstellen kann.

Mein Programm konvertiert Strings in Floats ala

Code: Alles auswählen

 
  f := strtofloat('1.0');
 


Natürlich habe ich im OnCreate ein

Code: Alles auswählen

 
  FormatSettings.DecimalSeparator := '.';   
 


Umstellen tue ich es nie mehr und doch bekomme ich nach einiger Nutzung immer eine AV nach dem Motto "1.0" is not a valid float.

Zum Nachstellen folgenden Code :

Code: Alles auswählen

 
Unit Unit1;
 
{$MODE objfpc}{$H+}
 
Interface
 
Uses
  Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls;
 
Type
 
  { TForm1 }
 
  TForm1 = Class(TForm)
    Button1: TButton;
    Procedure Button1Click(Sender: TObject);
    Procedure FormCreate(Sender: TObject);
  private
    { private declarations }
  public
    { public declarations }
  End;
 
Var
  Form1: TForm1;
 
Implementation
 
{$R *.lfm}
 
{ TForm1 }
 
Procedure TForm1.FormCreate(Sender: TObject);
Begin
  FormatSettings.DecimalSeparator := '.';
End;
 
Procedure TForm1.Button1Click(Sender: TObject);
Begin
  showmessage('FS : ' + FormatSettings.DecimalSeparator);
End;
 
End.
 


Des weiteren habe ich ein Deutsches Windows7, das Lazarus Programm wurde kompiliert unter einem Deutschen WinXP (default separator ist dort ',')
Wenn ich nun das Programm starte bekomme ich erwartungsgemäß die Meldung "FS : .". Den Bug erzeugen kann ich, wenn ich mittels WIN+L den Rechner Sperre und mich dann wieder einlogge. Danach kommt die Meldung "FS : ,"
Lazarus SVN Revision war : 54278
FPC Version : 3.0.2

Kann das jemand erklären / Reproduzieren ?
Muss ich in Zukunft in meine Programme einen Event "OnRelogin" einbauen der den DecimalSeparator wieder korrigiert ? Wie löst ihr das ?
Ist das evtl doch ein BUG ?

Unter Linux habe ich den Bug nicht, allerdings sind alle meine Linuxe auch default auf Eng -> Damit ist der DecimalSeparator eh schon auf "."

[Edit]
Selber Fehler reproduzierbar mit Delphi XE10 kompiliert und getestet unter Windows 7
--
Just try it

Benutzeravatar
corpsman
Lazarusforum e. V.
Beiträge: 1496
Registriert: Sa 28. Feb 2009, 08:54
OS, Lazarus, FPC: Linux Mint Mate, Lazarus GIT Head, FPC 3.0
CPU-Target: 64Bit
Wohnort: Stuttgart
Kontaktdaten:

Re: Erfahrungsbericht/ Bug FormatSettings.DecimalSeparator

Beitrag von corpsman »

Also wenn man mal weis, wonach man suchen mus ...

Zumindest für Windows gobts das hier :

Code: Alles auswählen

 
{$IFDEF Windows}
  Application.UpdateFormatSettings := false;
{$ENDIF}
 


Gemäß https://stackoverflow.com/questions/981 ... ons-to-use

Passiert das tatsächlich immer, wenn der User geswitched wird.
Am besten ist wohl, wenn man sich in seiner Anwendung eine "Globale"

Code: Alles auswählen

 
var
  myFormatSettings: TFormatSettings;
 

macht und gibt diese an alle Routinen die man so nutzt mit.
=> Volle Kontrolle, aber doch eine ganze menge an Komfort welchen man hier verliert
--
Just try it

mse
Beiträge: 2013
Registriert: Do 16. Okt 2008, 10:22
OS, Lazarus, FPC: Linux,Windows,FreeBSD,(MSEide+MSEgui 4.6,git master FPC 3.0.4,fixes_3_0)
CPU-Target: x86,x64,ARM

Re: Erfahrungsbericht/ Bug FormatSettings.DecimalSeparator

Beitrag von mse »

StrToFloat() gibt es in zwei Ausführungen:

Code: Alles auswählen

 
Function StrToFloat(Const S : String) : Extended;
Function StrToFloat(Const S : String; Const FormatSettings: TFormatSettings) : Extended;
 

In der Zweiten kann man eigene TFormatSettings übergeben, welche vom System nicht verändert werden. Die bei der ersten Form verwendeten DefaultFormatSettings werden den Systemeinstellungen nachgeführt. Offensichtlich löst Windows beim Einloggen einen Nachführvorgang aus -> bei festem Format sollten die Versionen der Konvertierungsfunktionen mit FormatSettings Parameter verwendet werden.
Eine Funktion string->real welche immer '.' als Dezimaltrenner verwendet ist "val":
https://www.freepascal.org/docs-html/cu ... m/val.html
Das Gegenstück dazu ist "str":
https://www.freepascal.org/docs-html/cu ... m/str.html
Edit: Wie du ja selbst herausgefunden hast. :-)
Zuletzt geändert von mse am Do 27. Jul 2017, 07:56, insgesamt 1-mal geändert.

Benutzeravatar
corpsman
Lazarusforum e. V.
Beiträge: 1496
Registriert: Sa 28. Feb 2009, 08:54
OS, Lazarus, FPC: Linux Mint Mate, Lazarus GIT Head, FPC 3.0
CPU-Target: 64Bit
Wohnort: Stuttgart
Kontaktdaten:

Re: Erfahrungsbericht/ Bug FormatSettings.DecimalSeparator

Beitrag von corpsman »

Stelle das nun komplett um auf

Code: Alles auswählen

 
  strtofloat('1.0', DefFormat);   
 


So was geht dann leider auch nicht mehr :/

Code: Alles auswählen

 
s := SQLQuery1.Fields[*].AsString; // Wenn Fiels[*] ein Float ist, denn man aber als String raus reichen will
 


Na da hab ich wieder ne menge zu Tun bis das alles wieder sauber läuft. Immerhin weis ich nun woran es liegt, ...
--
Just try it

wp_xyz
Beiträge: 4869
Registriert: Fr 8. Apr 2011, 09:01

Re: Erfahrungsbericht/ Bug FormatSettings.DecimalSeparator

Beitrag von wp_xyz »

Die Frage ist: Wie kommt der Dezimalpunkt überhaupt in diesen String?

(1) Weil du als Programmierer meinst, Dezimalzahlen müssten mit Dezimalpunkt eingegeben werden? Dann stelle die Ländereinstellungen deines Betriebssystems entsprechend um, und du bist dieses "Problem" ein für alle mal los, nicht nur für dieses, sondern auch für alle anderen Programme. Sobald dein Programm aber auch von anderen Personen als dir selbst benutzt werden soll/kann, finde ich die Änderung der globalen FormatSettings in einem Programm unpassend und verwirrend. Denn es gibt nun mal Länder, in denen Dezimalzahlen mit Komma geschrieben werden, und das lernt man so schon in der Grundschule. Ein Programm, das die Gewohnheiten eines Benutzers ignoriert und ihm andere Einstellungen aufzwingt, ist benutzerunfreundlich und daher letztendlich unprofessionell.

(2) Weil du Dateien lesen/schreiben musst, die für alle Ländereinstellungen ohne Probleme lesbar sein sollen, also einen Dezimalpunkt enthalten? Dann würde ich zu Beginn der Lese/Schreibroutine eine lokale Kopie der FormatSettings erzeugen, dort den Dezimaltrenner auf Punkt setzen und diese lokalen Formatsettings in der String-Zahl-Konvertierungsroutine als letzten Parameter verwenden. Oder falls du dir sparen willst, alle Konvertierungs-Aufrufe zu ändern, kannst du auch die globalen FormatSettings umstellen, musst das aber am Ende wieder zurückstellen, am besten in einem try-finally-Block.

Code: Alles auswählen

procedure ReadSettings(AFilename: String);
var
  ds: Char;
begin
  ds := FormatSettings.DecimalSeparator;
  FormatSettings.DecimalSeparator := '.'
  try
    ...  // Datei einlesen
  finally
    FormatSettings.DecimalSeparator := ds;
  end;
end;

Soner
Beiträge: 623
Registriert: Do 27. Sep 2012, 00:07
OS, Lazarus, FPC: Win10Pro-64Bit, Immer letzte Lazarus Release mit SVN-Fixes
CPU-Target: x86_64-win64
Wohnort: Hamburg

Re: Erfahrungsbericht/ Bug FormatSettings.DecimalSeparator

Beitrag von Soner »

Ich ändere Formatsettings nie, wenn ich
und zu Floats mit '.' brauche wie z.B. in direkte SQL-Befehle, dann ersetze ich ',' durch '.' und benutze val. Ersetzen nur wenn das defaultseperator ungleich '.' Ist . İch have noch nie Ärger damit gehabt.
Auch Tausenderseparator ersetzen nicht vergessen.

Timm Thaler
Beiträge: 1224
Registriert: So 20. Mär 2016, 22:14
OS, Lazarus, FPC: Win7-64bit Laz1.9.0 FPC3.1.1 für Win, RPi, AVR embedded
CPU-Target: Raspberry Pi 3

Re: Erfahrungsbericht/ Bug FormatSettings.DecimalSeparator

Beitrag von Timm Thaler »

wp_xyz hat geschrieben:Die Frage ist: Wie kommt der Dezimalpunkt überhaupt in diesen String?


Bei mir zum Beispiel über die RS232 aus einem externen Gerät. Da ist Dezimalseparator "." und Zahlenseparator ",". Und das kann ich auch nicht ändern.

Manchmal muss man also einfach da durch. Aber dass das automatisch wieder umgestellt werden kann wusste ich auch noch nicht. Ist das unter Linux auch so?

wp_xyz
Beiträge: 4869
Registriert: Fr 8. Apr 2011, 09:01

Re: Erfahrungsbericht/ Bug FormatSettings.DecimalSeparator

Beitrag von wp_xyz »

Timm Thaler hat geschrieben:
wp_xyz hat geschrieben:Die Frage ist: Wie kommt der Dezimalpunkt überhaupt in diesen String?

Bei mir zum Beispiel über die RS232 aus einem externen Gerät. Da ist Dezimalseparator "." und Zahlenseparator ",". Und das kann ich auch nicht ändern.

Klar. Das wäre entsprechend dem Fall einer zu lesenden Datei. Mache dir eine lokale Kopie der FormatSettings mit Dezimalpunkt als Separator, und verwende diese in den StrToFloat-Aufrufen.

Timm Thaler hat geschrieben:Manchmal muss man also einfach da durch. Aber dass das automatisch wieder umgestellt werden kann wusste ich auch noch nicht. Ist das unter Linux auch so?

"das ... umgestellt"? Was meinst du?

Benutzeravatar
corpsman
Lazarusforum e. V.
Beiträge: 1496
Registriert: Sa 28. Feb 2009, 08:54
OS, Lazarus, FPC: Linux Mint Mate, Lazarus GIT Head, FPC 3.0
CPU-Target: 64Bit
Wohnort: Stuttgart
Kontaktdaten:

Re: Erfahrungsbericht/ Bug FormatSettings.DecimalSeparator

Beitrag von corpsman »

@wp_xyz

ich habe den Fall (2)
Mein Program arbeitet Plattform unabhängig auf Windows / Linux und De / En. Dabei müssen die Konfig Files überall geöffnet werden können. Deswegen habe ich da bisher immer alles auf '.' gestellt gehabt
=> Und ja es war so Ignorant, das es die Lokalen Einstellungen ignoriert hat. Rechtfertigen kann ich das nur dadurch, das meine Programme Grundsätzlich in English gehalten werden und daher dann die Zahlen auch in Englisch schreiben.

@Soner
So gings mir auch, ich habe nun ewig rumgesucht bis ich da mal drauf kam, dass Windwos die Formatsettings verändert.

Deswegen auch der Post um es anderen auch ins Gedächtnis zu Rufen ;)
--
Just try it

Mathias
Beiträge: 6160
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: Erfahrungsbericht/ Bug FormatSettings.DecimalSeparator

Beitrag von Mathias »

Deswegen habe ich da bisher immer alles auf '.' gestellt gehabt

Wen es immer ein '.' ist, dann kannst du das Ganze ohne Ländereinstellungen, etc, umgehen.

Nimm einfach Str und Val, da wird immer ein Punkt verlangt.
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Antworten