![]() |
Record als Result einer Funktion
Hallo,
wenn ich einen Record deklariere und diesen dann einer Funktion als Result zuordne, werden alle Werte innerhalb des Records auf True gesetzt. Warum, weiß ich nicht. Hier ein Beispiel:
Code:
Rufe ich die funktion nun auf, ist alles vom Result auch True.
type
TTest_Result = record Test_a : Boolean; Test_b : Boolean; Test_c : Boolean; end; function test(a:integer):TTest_Result; function test(a:integer):TTest_Result; begin Result.Test_a := True; end; Eine Zuweisung mittels Result.Test_b := False; z.B. innerhalb der function oder vorher aus dem Aufruf der function heraus, bringt auch nichts. Warum passiert das und wie behebe ich diesen Fehler? LG Mathias |
AW: Record als Result einer Funktion
Versuch mal so. Funktioniert bei mir wie gewünscht
Booleans sind, wenn sie vorher nicht initialisiert werden, immer auf True. Jedenfalls bei MIR unter 10.3.3.
Delphi-Quellcode:
function test: TTest_Result;
begin Result.Test_a := True; Result.Test_b := False; Result.Test_c := True; end; // was du in der Funktion test am Ende machst, bleibt dir überlassen procedure TForm1.Button2Click(Sender: TObject); var X: TTest_Result; begin X := test; showmessage( BoolToStr(X.Test_a, True)+sLineBreak+ BoolToStr(X.Test_b, True)+sLineBreak+ BoolToStr(X.Test_c, True) ); end; |
AW: Record als Result einer Funktion
Kann diesen Fehler nicht reproduzieren. Das Problem muss also wo anders liegen. Bei mir Funktioniert der von dir aufgeführte Code problemlos, und es wird
Delphi-Quellcode:
zurückgegeben.
(True, False, False).
|
AW: Record als Result einer Funktion
Zitat:
Zitat:
|
AW: Record als Result einer Funktion
Zitat:
Delphi-Quellcode:
. Außerdem werden initialisierte Variablen immer mit 0 beschrieben, so ist das auch in der aktuellen OH nachzulesen.
False
Habe gerade kein 10.3.3 zur Hand, wäre aber definitiv ein Bug, wenn es so wie von dir beschrieben sich verhält. |
AW: Record als Result einer Funktion
Da du den anderen Feldern von result keine Werte zuweist, ist deren Inhalt eher zufällig.
|
AW: Record als Result einer Funktion
Zitat:
Ich: 10.3.3. Vielleicht gibt es da Unterschiede oder einen Bug. Ich hatte immer alle auf True, obwohl ich persönlich eher False erwartet hätte. |
AW: Record als Result einer Funktion
Zitat:
|
AW: Record als Result einer Funktion
Um das abzukürzen und nicht 10 Seiten an Diskussionen zu erzeugen:
einfach alles initialisieren oder setzen. Dann gibt es auch kein Problem. Aber bevor wir hier nicht sehen wie test() aufgerufen wird, kann man eh nix sagen. |
AW: Record als Result einer Funktion
Zitat:
Ansonsten ist der Wert halt zufällig, und da alles außer 0 als
Delphi-Quellcode:
ausgewertet wird, erhältst du halt meistens das. Das wäre in dem Fall aber immer noch Zufall und nichts, auf das du dich verlassen kannst/solltest!
True
EDIT: (kleine Ergänzung): Automatisch initialisierte Variablen sind Strings, dynamische Arrays, Objektfelder und globale Variablen. |
AW: Record als Result einer Funktion
Zitat:
|
AW: Record als Result einer Funktion
Dieser Record (über 4 Byte) wird, wie auch bei Strings, DynArrays, Interfaces und alle Typen größer als 4 Byte (NativeInt/Pointer) als VAR-Para,eter durchgereicht.
Die Initialisierung hängt also vom Aufrufer ab und dort ist es meistens eine lokale Variable in einer Prozedur. Auch in einer Schleife (For/Repeat) ist sowas selten so initialisiert, wie du es denkst. |
AW: Record als Result einer Funktion
Zitat:
Delphi-Quellcode:
sein müssen, sondern es nur meistens halt durch Zufall bei dir waren.
True
|
AW: Record als Result einer Funktion
Liste der Anhänge anzeigen (Anzahl: 1)
Ich habe mal mein Testprojekt angehängt.
Bitte nicht wundern, wenn hier und da noch etwas im Code technisch nicht ganz sauber ist.
Code:
Mit dieser Hilfsprocedure klappt es nun auch.
procedure init_Result( var _Result : TDB_Result );
begin >> Hier mal ein Exit; rein machen und bitte testen. Als Fremdkomponenten benutze ich ABSDatabase, ABSQuery, ABSTable. LG Mathias Edit: Quellcode hinzugefügt
Code:
unit Unit1;
interface uses Unit_ABS_DBFunctions, Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Data.DB, ABSMain, Vcl.Grids, Vcl.DBGrids, Vcl.StdCtrls; type TForm1 = class( TForm ) DBGrid1 : TDBGrid; ABSDatabase1 : TABSDatabase; ABSTable1 : TABSTable; DataSource1 : TDataSource; Button1 : TButton; ABSQuery1 : TABSQuery; Button2 : TButton; Button3 : TButton; Memo1 : TMemo; Button4 : TButton; Button5 : TButton; Button6 : TButton; procedure Button1Click( Sender : TObject ); procedure Button3Click( Sender : TObject ); procedure Button4Click( Sender : TObject ); procedure Button2Click( Sender : TObject ); procedure FormCreate( Sender : TObject ); procedure Button5Click( Sender : TObject ); procedure Button6Click( Sender : TObject ); private { Private-Deklarationen } public { Public-Deklarationen } end; var Form1 : TForm1; a_SelfPath : string; { Datenbankpfad } a_DataBasePath : string; a_DatabaseFileName : string; const DatabaseFileName = 'test_db'; DatabaseExt = '.trm'; DatabaseName = 'DB'; { Fields Table Test } TableName_Test = 'test_table'; Labels_DB : TArray< string > = [ 'nummer', 'spalte2', 'spalte3', 'spalte4', 'spalte5', 'ALF', 'eeeeeee' ]; Labels_DB_Type_Query : TArray< string > = [ 'AUTOINC NOT NULL', 'VARCHAR(%d) NOT NULL', 'VARCHAR(%d)', 'VARCHAR(%d)', 'VARCHAR(%d)', 'VARCHAR(%d)', 'AUTOINC' ]; Labels_DB_Size_Query : TArray< Integer > = [ 0, 2, 2, 4, 2, 2, 0 ]; Indizes_DB_Query_n : TArray< TArray< string > > = [ [ 'pk_number', 'CREATE UNIQUE INDEX pk_number ON test_table (nummer);' ], [ 'i_spalte2', 'CREATE INDEX i_spalte2 ON test_table (spalte2,spalte3 );' ], [ 'i_spalte4', 'CREATE INDEX i_spalte4 ON test_table (spalte2,spalte3 );' ], [ 'i_spalte3', 'CREATE INDEX i_spalte3 ON test_table (spalte2,spalte3 );' ] ]; implementation {$R *.dfm} procedure TForm1.Button1Click( Sender : TObject ); var i : Integer; begin if trim( ABSDatabase1.DatabaseFileName ) <> '' then if ( FileExists( ABSDatabase1.DatabaseFileName ) ) then if trim( ABSTable1.TableName ) <> '' then if ABSTable1.Database.Exists then try ABSTable1.FieldDefs.BeginUpdate; ABSTable1.DisableControls; for i := 1 to 7 do begin ABSTable1.Append; ABSTable1.FieldByName( Labels_DB[ 1 ] ).AsInteger := random( 300 ) + 1700; ABSTable1.FieldByName( Labels_DB[ 2 ] ).AsInteger := random( 300 ) + 1700; ABSTable1.FieldByName( Labels_DB[ 3 ] ).AsInteger := random( 300 ) + 1700; ABSTable1.FieldByName( Labels_DB[ 4 ] ).AsString := format( '%d,%2.2d', [ random( 50 ) + 5, random( 99 ) ] ); ABSTable1.FieldByName( Labels_DB[ 5 ] ).AsString := '5'; ABSTable1.Post; end; ABSTable1.EnableControls; ABSTable1.FieldDefs.EndUpdate; finally Memo1.Lines.Add( '' ); Memo1.Lines.Add( '- Datensätze wurden hinzugefügt -' ); end; if ( trim( ABSDatabase1.DatabaseFileName ) = '' ) or ( not FileExists( ABSDatabase1.DatabaseFileName ) ) then begin Memo1.Lines.Add( '' ); Memo1.Lines.Add( '- Keine Datenbank vorhanden - ' ); Memo1.Lines.Add( '(Kann keine Daten hinzufügen)' ); end; if ( trim( ABSTable1.TableName ) = '' ) or ( not ABSTable1.Database.Exists ) then begin Memo1.Lines.Add( '' ); Memo1.Lines.Add( '- Keine Tabelle vorhanden - ' ); Memo1.Lines.Add( '(Kann keine Daten hinzufügen)' ); end; end; procedure TForm1.Button2Click( Sender : TObject ); var DB_Result : TDB_Result; begin a_SelfPath := IncludeTrailingPathDelimiter( ExtractFilePath( ParamStr( 0 ) ) ); a_DataBasePath := a_SelfPath; a_DatabaseFileName := a_DataBasePath + DatabaseFileName + DatabaseExt; init_Result( DB_Result ); DB_Result := init_DatabaseABS( ABSDatabase1, ABSTable1, ABSQuery1, a_DatabaseFileName, DatabaseName ); Memo1.Lines.Add( '' ); if DB_Result.Create_Database then Memo1.Lines.Add( '- Datenbank wird neu erstellt -' ); if DB_Result.Open_DataBase then Memo1.Lines.Add( '- Datenbank ist vorhanden, wird geöffnet -' ); DB_Result := init_TableABS_Query( ABSDatabase1, ABSTable1, ABSQuery1, TableName_Test, Labels_DB, Labels_DB_Type_Query, Labels_DB_Size_Query, Indizes_DB_Query_n ); Memo1.Lines.Add( '' ); if DB_Result.Create_Table then Memo1.Lines.Add( '- Tabelle wurde neu erstellt -' ); if DB_Result.Open_Table then Memo1.Lines.Add( '- Tabelle war vorhanden, wurde geöffnet -' ); if DB_Result.Add_Table then Memo1.Lines.Add( '- Tabelle wurde hinzugefügt -' ); if DB_Result.Create_Field then Memo1.Lines.Add( '- Feld(er) wurde(n) zur Tabelle hinzugefügt -' ); if DB_Result.Change_Field then Memo1.Lines.Add( '- Feld(er) in der Tabelle wurde(n) aktualisiert -' ); if DB_Result.Delete_Field then Memo1.Lines.Add( '- Felde(r) in der Tabelle wurde(n) gelöscht -' ); if DB_Result.Create_Index then Memo1.Lines.Add( '- Index/Indizes wurde(n) neu erstellt -' ); if DB_Result.Add_Index then Memo1.Lines.Add( '- Index/Indizes wurde(n) hinzugefügt -' ); if DB_Result.Change_Index then Memo1.Lines.Add( '- Index/Indizes wurde(n) aktualisiert -' ); if DB_Result.Rebuild_Index then Memo1.Lines.Add( '- Index/Indizes wurde(n) neu aufgebaut -' ); end; procedure TForm1.Button3Click( Sender : TObject ); begin ABSTable1.Close; ABSQuery1.Close; ABSDatabase1.Close; ABSTable1.IndexDefs.Clear; ABSQuery1.IndexDefs.Clear; ABSDatabase1.DeleteDatabase; Memo1.Lines.Add( '' ); Memo1.Lines.Add( '- Datenbank wurde gelöscht -' ); end; procedure TForm1.Button4Click( Sender : TObject ); var x : Integer; begin if trim( ABSDatabase1.DatabaseFileName ) <> '' then if ( FileExists( ABSDatabase1.DatabaseFileName ) ) then if trim( ABSTable1.TableName ) <> '' then if ABSTable1.Database.Exists then try ABSTable1.IndexDefs.Update; finally Memo1.Lines.Add( '' ); Memo1.Lines.Add( 'Indexfields:' ); for x := 0 to pred( ABSTable1.IndexDefs.Count ) do Memo1.Lines.Add( format( '%s[%d] (%d): %s', [ 'Indexname', x, Succ( x ), ABSTable1.IndexDefs[ x ].Name ] ) ); end; if ( trim( ABSDatabase1.DatabaseFileName ) = '' ) or ( not FileExists( ABSDatabase1.DatabaseFileName ) ) then begin Memo1.Lines.Add( '' ); Memo1.Lines.Add( '- Keine Datenbank vorhanden - ' ); Memo1.Lines.Add( '(Kann keine Idexfelder abrufen)' ); end; if ( trim( ABSTable1.TableName ) = '' ) or ( not ABSTable1.Database.Exists ) then begin Memo1.Lines.Add( '' ); Memo1.Lines.Add( '- Keine Tabelle vorhanden - ' ); Memo1.Lines.Add( '(Kann keine Idexfelder abrufen)' ); end; end; procedure TForm1.Button5Click( Sender : TObject ); begin Memo1.Lines.Clear; end; procedure TForm1.Button6Click( Sender : TObject ); var x : Integer; begin if trim( ABSDatabase1.DatabaseFileName ) <> '' then if ( FileExists( ABSDatabase1.DatabaseFileName ) ) then if trim( ABSTable1.TableName ) <> '' then if ABSTable1.Database.Exists then try ABSTable1.IndexDefs.Update; finally Memo1.Lines.Add( '' ); Memo1.Lines.Add( 'FieldTypes:' ); for x := 0 to pred( ABSTable1.FieldDefs.Count ) do Memo1.Lines.Add( format( '%s[%d]: %s | %s: %s(%d)', [ 'FieldName', x, ABSTable1.FieldDefs[ x ].Name, 'FieldType:', FieldTyp2String( ABSTable1.Fields[ x ].DataType ), ABSTable1.Fields[ x ].Size ] ) ); end; if ( trim( ABSDatabase1.DatabaseFileName ) = '' ) or ( not FileExists( ABSDatabase1.DatabaseFileName ) ) then begin Memo1.Lines.Add( '' ); Memo1.Lines.Add( '- Keine Datenbank vorhanden - ' ); Memo1.Lines.Add( '(Kann keine FeldTypen abrufen)' ); end; if ( trim( ABSTable1.TableName ) = '' ) or ( not ABSTable1.Database.Exists ) then begin Memo1.Lines.Add( '' ); Memo1.Lines.Add( '- Keine Tabelle vorhanden - ' ); Memo1.Lines.Add( '(Kann keine FeldTypen abrufen)' ); end; end; procedure TForm1.FormCreate( Sender : TObject ); begin Button5Click( nil ); // Button2Click( nil ); // Button4Click( nil ); end; end.
Code:
unit Unit_ABS_DBFunctions;
interface uses ABSSecurity, ABSMain, Data.DB, System.Classes, System.StrUtils, System.Sysutils, System.TypInfo, System.UITypes, Vcl.Controls, Vcl.Dialogs; { Datenbank-Rückgabe Ergebnisse von Funktionen } type TDB_Result = record Open_DataBase : Boolean; Create_Database : Boolean; Open_Table : Boolean; Create_Table : Boolean; Add_Table : Boolean; Create_Field : Boolean; Add_Field : Boolean; Change_Field : Boolean; Delete_Field : Boolean; Create_Index : Boolean; Add_Index : Boolean; Change_Index : Boolean; Rebuild_Index : Boolean; RestructureResult : Boolean; end; type TDB_Settings = record Show_Errors : Boolean; Show_Questions : Boolean; Delete_Fields : Boolean; end; var DB_Settings : TDB_Settings; const BR = #10#13; DBR = BR + BR; Question_Restructure_Table1 = 'Ein Programmupdate wurde kürzlich installiert. Die Datenbank ''%s'' muss aktualisiert werden. Dieser Vorgang kann länger dauern.'; Question_Restructure_Table2 = '!! Befolgen Sie diesen Hinweis unbedingt !!' + DBR + 'Bitte beenden Sie das Programm nicht, auch wenn es aussieht, als würde es festhängen. Bitte melden Sie keinen weiteren Benutzer im Netzwerk an.' + DBR + 'Die Datenbank kann sonst beschädigt werden.'; Error_C_DB_Create = 'Fehler: Datenbank [%s] konnte nicht erstellt werden!'; Error_C_Table_Open = 'Die Tabelle [%s] konnte nicht geöffnet werden.'; Error_C_Table_Create = 'Die Tabelle [%s] konnte nicht erstellt werden!'; Error_C_Index_Rebuild = 'Indexfehler beim Neuaufbeu in Tabelle [%s]!'; Error_C_Table_Restructure_AddField = 'Fehler bei der Restrukturierung. Das Tabellenfeld [%s] konnte nicht zur Tabelle [%s] hinzugefügt werden.'; Error_C_Table_DropField = 'Fehler beim Löschen von Tabellenfeld [%s] in Tabelle [%s]!'; Error_C_Table_Change_TypeSize = 'Fehler beim Ändern eines FeldTypes oder Feldgröße im Feld [%s]. Betrifft Tabelle [%s]!'; Question_C_Table_FieldSize = 'Ein bestehendes Feld [%s] soll verkleinert werden. Dadurch kann es zu Datenverlust kommen. Soll der Vorgang fortgesetzt werden?'; procedure init_Result( var _Result : TDB_Result ); function FieldTyp2String( _ft : TFieldType ) : string; function init_DatabaseABS( _DataBase : TABSDatabase; _Table : TABSTable; _Query : TABSQuery; _DatabaseFileName : string; _DatabaseName : string; _MultiUser : Boolean = True; _Encrypted : Boolean = False; _CryptoAlgorithm : TABSCryptoAlgorithm = craRijndael_256; _CryptoPassword : string = ''; _PageSize : Integer = 128; _PageCountInExtent : Integer = 8; _MaxConnections : Integer = 483 ) : TDB_Result; function init_TableABS_Query( _DataBase : TABSDatabase; _Table : TABSTable; _Query : TABSQuery; _Table_Name : string; _Labels_DB : TArray< string >; _Labels_DB_Type_Query : TArray< string >; _Labels_DB_Size_Query : TArray< Integer >; _Indizes_DB_Query : TArray< TArray< string > > ) : TDB_Result; function Restructure_Table_Query( _DataBase : TABSDatabase; _Query : TABSQuery; _Table_Name : string; _Labels_DB : TArray< string >; _Labels_DB_Type_Query : TArray< string >; _Labels_DB_Size_Query : TArray< Integer >; _Indizes_DB_Query : TArray< TArray< string > > ) : TDB_Result; function Create_Table_Query( _Table : TABSTable; _Query : TABSQuery; _Table_Name : string; _Labels_DB : TArray< string >; _Labels_DB_Type_Query : TArray< string >; _Labels_DB_Size_Query : TArray< Integer > ) : TDB_Result; function Index_Exists( _Table : TABSTable; const _IndexName : string ) : Boolean; function Rebuild_Index_Query( _Table : TABSTable; _Query : TABSQuery; _Labels_DB : TArray< string >; _Labels_DB_Type_Query : TArray< string >; _Indizes_DB_Query : TArray< TArray< string > > ) : TDB_Result; implementation procedure init_Result( var _Result : TDB_Result ); begin >> Hier mal ein Exit; rein machen und bitte testen. _Result.Open_DataBase := False; _Result.Create_Database := False; _Result.Open_Table := False; _Result.Create_Table := False; _Result.Add_Table := False; _Result.Create_Field := False; _Result.Add_Field := False; _Result.Change_Field := False; _Result.Delete_Field := False; _Result.Create_Index := False; _Result.Add_Index := False; _Result.Change_Index := False; _Result.Rebuild_Index := False; _Result.RestructureResult := False; end; function FieldTyp2String( _ft : TFieldType ) : string; begin case _ft of ftAutoinc : Result := 'AUTOINC'; ftBlob : Result := 'BLOB'; ftBytes : Result := 'BYTES'; ftCurrency : Result := 'CURRENCY'; ftDate : Result := 'DATE'; ftDateTime : Result := 'DATETIME'; ftFloat : Result := 'FLOAT'; ftFmtMemo : Result := 'FORMATTEDMEMO'; ftGraphic : Result := 'GRAPHIC'; ftGUID : Result := 'GUID'; ftInteger : Result := 'INTEGER'; ftLargeInt : Result := 'LARGEINT'; ftBoolean : Result := 'BOOLEAN'; ftMemo : Result := 'MEMO'; ftSmallint : Result := 'SMALLINT'; ftString : Result := 'VARCHAR'; ftFixedChar : Result := 'FIXEDCHAR'; ftTime : Result := 'TIME'; ftTimeStamp : Result := 'TIMESTAMP'; ftVarBytes : Result := 'VARBYTES'; ftWideString : Result := 'WIDESTRING'; ftWord : Result := 'WORD' else Result := 'unbekannt'; end; end; function init_DatabaseABS( _DataBase : TABSDatabase; _Table : TABSTable; _Query : TABSQuery; _DatabaseFileName : string; _DatabaseName : string; _MultiUser : Boolean = True; _Encrypted : Boolean = False; _CryptoAlgorithm : TABSCryptoAlgorithm = craRijndael_256; _CryptoPassword : string = ''; _PageSize : Integer = 128; _PageCountInExtent : Integer = 8; _MaxConnections : Integer = 483 ) : TDB_Result; begin _DataBase.DatabaseName := _DatabaseName; _Table.DatabaseName := _DatabaseName; _Query.DatabaseName := _DatabaseName; _Table.Close; _Query.Close; _DataBase.Close; _DataBase.DatabaseFileName := _DatabaseFileName; try if ( not _DataBase.Exists ) or ( not Fileexists( _DataBase.DatabaseFileName ) ) then begin if _Encrypted and ( Length( Trim( _CryptoPassword ) ) > 0 ) then begin _DataBase.CryptoAlgorithm := _CryptoAlgorithm; _DataBase.Password := _CryptoPassword; end; _DataBase.CreateDatabase; Result.Create_Database := True; end; if _MultiUser then _DataBase.MultiUser := True; _DataBase.Open; Result.Open_DataBase := True; except if DB_Settings.Show_Errors then ShowMessage( Format( Error_C_DB_Create, [ _DatabaseName ] ) ); end; end; function init_TableABS_Query( _DataBase : TABSDatabase; _Table : TABSTable; _Query : TABSQuery; _Table_Name : string; _Labels_DB : TArray< string >; _Labels_DB_Type_Query : TArray< string >; _Labels_DB_Size_Query : TArray< Integer >; _Indizes_DB_Query : TArray< TArray< string > > ) : TDB_Result; begin _Table.Close; _Query.Close; _Table.TableName := _Table_Name; _Table.DatabaseName := _DataBase.DatabaseName; _Query.DatabaseName := _DataBase.DatabaseName; { Wenn schon vorhanden - öffnen und Feldprüfung } if _Table.Exists then try _Table.Close; Result := Restructure_Table_Query( _DataBase, _Query, _Table_Name, _Labels_DB, _Labels_DB_Type_Query, _Labels_DB_Size_Query, _Indizes_DB_Query ); _Table.Open; _Table.Refresh; Result.Open_Table := True; if not Result.RestructureResult then Exit; except if DB_Settings.Show_Errors then ShowMessage( Format( Error_C_Table_Open, [ _Table_Name ] ) ); end; { Wenn noch nicht vorhanden - erstellen } if not _Table.Exists then try Create_Table_Query( _Table, _Query, _Table_Name, _Labels_DB, _Labels_DB_Type_Query, _Labels_DB_Size_Query ); _Table.Refresh; Result.Create_Table := True; except if DB_Settings.Show_Errors then ShowMessage( Format( Error_C_Table_Create, [ _Table_Name ] ) ); end; { Alle Indizes (Index) - Suchfelder initialisieren } try Rebuild_Index_Query( _Table, _Query, _Labels_DB, _Labels_DB_Type_Query, _Indizes_DB_Query ); Result.Rebuild_Index := True; except if DB_Settings.Show_Errors then ShowMessage( Format( Error_C_Index_Rebuild, [ _Table_Name ] ) ); end; end; function Restructure_Table_Query( _DataBase : TABSDatabase; _Query : TABSQuery; _Table_Name : string; _Labels_DB : TArray< string >; _Labels_DB_Type_Query : TArray< string >; _Labels_DB_Size_Query : TArray< Integer >; _Indizes_DB_Query : TArray< TArray< string > > ) : TDB_Result; var x : Integer; Dummy_Bool : Boolean; field_old_type, field_new_type : string; field_old_size, field_new_size : Integer; begin { Tabellenfelder prüfen, gegebenenfalls anlegen } for x := low( _Labels_DB ) to high( _Labels_DB ) do begin { Tabellenfeld hinzufügen, wenn es nicht existiert } try _Query.SQL.Text := 'ALTER TABLE ' + _Table_Name + ' ADD (IF NOT EXISTS ' + _Labels_DB[ x ] + ' ' + Format( _Labels_DB_Type_Query[ x ], [ _Labels_DB_Size_Query[ x ] ] ) + ');'; _Query.ExecSQL; Result.Add_Field := True; except if DB_Settings.Show_Errors then ShowMessage( Format( Error_C_Table_Restructure_AddField, [ _Labels_DB[ x ], _Table_Name ] ) ); Exit; end; { Tabellenfeld hinzufügen, wenn es nicht existiert } { Wenn Tabellenfeld falsches Format oder Größe hat } _Query.RequestLive := True; _Query.SQL.Text := 'SELECT * From ' + _Table_Name + ' WHERE 1 = 0'; _Query.Open; field_old_type := FieldTyp2String( _Query.Fields[ x ].DataType ); field_old_size := _Query.Fields[ x ].Size; if pos( #32, _Labels_DB_Type_Query[ x ] ) = 0 then field_new_type := _Labels_DB_Type_Query[ x ]; if pos( #32, _Labels_DB_Type_Query[ x ] ) <> 0 then field_new_type := LeftStr( _Labels_DB_Type_Query[ x ], pos( #32, _Labels_DB_Type_Query[ x ] ) ); field_new_size := _Labels_DB_Size_Query[ x ]; Dummy_Bool := not ( ( field_new_size = field_old_size ) or ( field_new_size > field_old_size ) ); if field_new_size < field_old_size then if DB_Settings.Show_Questions then Dummy_Bool := MessageDLG( Question_C_Table_FieldSize, mtConfirmation, mbYesNo, 0 ) = mrYes; if field_new_size < field_old_size then if not DB_Settings.Show_Questions then Dummy_Bool := True; if ( ( field_old_type <> field_new_type ) or ( field_old_size <> field_new_size ) ) and Dummy_Bool then try _Query.SQL.Text := 'ALTER TABLE ' + _Table_Name + ' MODIFY (' + _Labels_DB[ x ] + ' ' + Format( _Labels_DB_Type_Query[ x ], [ _Labels_DB_Size_Query[ x ] ] ) + ');'; _Query.ExecSQL; Result.Change_Field := True; except if DB_Settings.Show_Errors then ShowMessage( Format( Error_C_Table_Change_TypeSize, [ _Labels_DB[ x ], _Table_Name ] ) ); Exit; end; { Wenn Tabellenfeld falsches Format hat } end; { Felder löschen, die in der Deklaration nicht mehr existieren } if DB_Settings.Delete_Fields then for x := _Query.FieldDefs.Count - 1 downto 0 do if not MatchStr( _Query.FieldDefs.Items[ x ].Name, _Labels_DB ) then try _Query.SQL.Text := 'ALTER TABLE ' + _Table_Name + ' DROP COLUMN ' + _Query.FieldDefs.Items[ x ].Name + ';'; _Query.ExecSQL; Result.Delete_Field := True; except if DB_Settings.Show_Errors then ShowMessage( Format( Error_C_Table_DropField, [ _Query.FieldDefs.Items[ x ].Name, _Table_Name ] ) ); end; end; function Create_Table_Query( _Table : TABSTable; _Query : TABSQuery; _Table_Name : string; _Labels_DB : TArray< string >; _Labels_DB_Type_Query : TArray< string >; _Labels_DB_Size_Query : TArray< Integer > ) : TDB_Result; var x : Integer; Dummy_SQL : string; begin if _Table.Exists then begin _Table.Open; _Table.Active := True; Result.Open_Table := True; end; if not _Table.Exists then try _Query.SQL.Clear; Dummy_SQL := ''; for x := low( _Labels_DB ) to high( _Labels_DB ) do begin if x <> low( _Labels_DB ) then Dummy_SQL := Dummy_SQL + ',' + DBR; Dummy_SQL := Dummy_SQL + Format( '%s %s', [ _Labels_DB[ x ], Format( _Labels_DB_Type_Query[ x ], [ _Labels_DB_Size_Query[ x ] ] ) ] ); end; _Query.SQL.Text := 'DROP TABLE IF EXISTS ' + _Table_Name + '; ' + DBR + 'CREATE TABLE ' + _Table_Name + ' (' + Dummy_SQL + ');'; _Query.ExecSQL; _Table.Open; _Table.Active := True; Result.Create_Table := True; except if DB_Settings.Show_Errors then ShowMessage( Format( Error_C_Table_Create, [ _Table_Name ] ) ); end; end; function Index_Exists( _Table : TABSTable; const _IndexName : string ) : Boolean; var IndexDef : TIndexDef; i : Integer; begin Result := False; for i := 0 to pred( _Table.IndexDefs.Count ) do begin IndexDef := _Table.IndexDefs[ i ]; if CompareText( IndexDef.Name, _IndexName ) = 0 then begin Result := True; break; end; end; end; function Rebuild_Index_Query( _Table : TABSTable; _Query : TABSQuery; _Labels_DB : TArray< string >; _Labels_DB_Type_Query : TArray< string >; _Indizes_DB_Query : TArray< TArray< string > > ) : TDB_Result; var Dummy_Int : Integer; Dummy_SQL : string; begin _Table.Open; _Table.IndexDefs.Update; { Alle Indexfelder durchgehen, SQL erzeugen } for Dummy_Int := low( _Indizes_DB_Query ) to high( _Indizes_DB_Query ) do if not Index_Exists( _Table, _Indizes_DB_Query[ Dummy_Int ][ 0 ] ) then Dummy_SQL := Dummy_SQL + _Indizes_DB_Query[ Dummy_Int ][ 1 ]; if Dummy_SQL <> '' then try _Query.SQL.Text := Dummy_SQL; _Query.ExecSQL; _Query.SQL.Clear; Result.Rebuild_Index := True; except if DB_Settings.Show_Errors then ShowMessage( Format( Error_C_Index_Rebuild, [ _Table.TableName ] ) ); end; _Query.IndexDefs.Update; _Table.IndexDefs.Update; _Table.Close; _Table.Open; end; end. |
AW: Record als Result einer Funktion
In deinem Code benutzt du die Werte von DB_Settings nur zum lesen. Die drei Werte werden zu keinem Zeitpunkt initialisiert. Ist das so gewollt?
|
AW: Record als Result einer Funktion
Zitat:
Zitat:
Der Witz: BR sind sind so 2 Zeilenumbrüche, aber wer denkt, dass 2 * 2 nun 4 ist, der wird enttäuscht, denn DBR sind so 3 Zeilenumbrüche. :stupid: :angle2: Wer es nicht kann, der sollte ![]() |
AW: Record als Result einer Funktion
Zitat:
[QUOTE=himitsu;1460666] Zitat:
Die von euch angesprochenen Probleme betreffen aber leider nicht das Hauptthema, um welches es mir geht. LG Mathias |
AW: Record als Result einer Funktion
Zitat:
|
AW: Record als Result einer Funktion
Zitat:
Warum sind Boolean von Haus aus True? |
AW: Record als Result einer Funktion
Zitat:
In der Realität ist der Speicher ja nicht wirklich zufällig belegt, sondern enthält das was vorher über eine andere Variable dort abgelegt wurde. Daher hat der vorherige Programmablauf entscheidenden Einfluss auf den Inhalt des Records. |
AW: Record als Result einer Funktion
Zitat:
|
AW: Record als Result einer Funktion
Hallo NoGAD,
Du könntest Deinen eigenen Boolean-Typ deklarieren, bei dem dieses Problem nicht auftritt:
Delphi-Quellcode:
Und schon sind Deine Variablen beim Anlegen & Löschen "automatisch" auf boUndef gesetzt.
Type
MyBoolean = (boUndef, boFalse, boTrue); Gruß, Andreas |
AW: Record als Result einer Funktion
Zitat:
Zitat:
Also im Prinzip ist es ach deiner Definition ein Variant, der von Haus aus erstmal NULL ist und anschließens True oder False (WordBool) aufnehmen kann. Mit dem Unterschied dass der Variant immer initialisiert ist und dein ENUM nicht. siehe auch ![]() |
AW: Record als Result einer Funktion
Lieben Dank an euch alle.
Da ich nur als Hobby programmiere, fehlen mir sicherlich wichtige Voraussetzungen, welche man durch eine entsprechende Ausbildung erhält. Lernen hingegen möchte ich immer. Daher freue ich mich, dass ich auch bei solchen Kleinigkeiten eines Besseren belehrt werde. :thumb: Bisher war ich auch immer der falschen Annahme erlegen, dass Boolean immer automatisch als False initialisiert werden. Falls noch jemand im Code eklatante Fehler, außer den bereits angesprochenen, findet, wäre ich über Rückmeldungen sehr erfreut. LG Mathias |
AW: Record als Result einer Funktion
Einfach angewöhnen alles zu initialisieren und das Standardverhalten kann einem egal sein. So mache ich es schon seit Ewigkeiten und bin bisher gut damit gefahren.
|
AW: Record als Result einer Funktion
Zitat:
Delphi 2010 = OK
Delphi-Quellcode:
lässt man die Initialisierung 'x := 0;' weg kommt diese Meldung Variable: 'x' wurde nicht initialisiert.
var
x, i: Integer; begin x := 0; for i := 0 to 10 do if i mod 2 then x := i; end; Delphi 10.3 = Warnung: Auf 'x' zugewiesener Wert wird niemals benutzt. Eine Faustregel gibt es nicht. |
AW: Record als Result einer Funktion
Zitat:
Delphi-Quellcode:
Bitte selber überprüfen.
program Aufzaehlungstyp_Initialisierung_Test_1;
{$APPTYPE CONSOLE} {$R *.res} uses System.SysUtils; Type MyBoolean = (boUndef, boFalse, boTrue); CONST MyBooleanStr: Array[MyBoolean] of String = ('Undefiniert', 'Nein', 'Ja'); n_Daten = 150; VAR MB: MyBoolean; MB_Array: Array[1..n_Daten] of MyBoolean; i : Integer; Begin Try // OHNE eigene Initialisierung: WriteLn('MB: MyBooleanStr[MB] = ', MyBooleanStr[MB]); WriteLn; For i:= 1 To n_Daten Do Begin WriteLn('MyBooleanStr[MB_Array[', i.ToString.PadLeft(3), ']] = ', MyBooleanStr[MB_Array[i]]); End; ReadLn; Except on E: Exception do Writeln(E.ClassName, ': ', E.Message); End; End. Gruß, Andreas |
AW: Record als Result einer Funktion
Und - damit wir beim Thema bleiben (Record als Result einer Funktion) - fügen wir noch folgenden Code zusätzlich ins obige Programm ein:
Delphi-Quellcode:
Auch dann funktioniert es.
Type
MB_Record = Record MB1: MyBoolean; MB2: MyBoolean; MB3: MyBoolean; MB4: MyBoolean; MB5: MyBoolean; MB6: MyBoolean; MB7: MyBoolean; End; ... VAR MB_Rec: MB_Record; ... WriteLn('MB_Rec.MB1 = ', MyBooleanStr[MB_Rec.MB1]); WriteLn('MB_Rec.MB2 = ', MyBooleanStr[MB_Rec.MB2]); WriteLn('MB_Rec.MB3 = ', MyBooleanStr[MB_Rec.MB3]); WriteLn('MB_Rec.MB4 = ', MyBooleanStr[MB_Rec.MB4]); WriteLn('MB_Rec.MB5 = ', MyBooleanStr[MB_Rec.MB5]); WriteLn('MB_Rec.MB6 = ', MyBooleanStr[MB_Rec.MB6]); WriteLn('MB_Rec.MB7 = ', MyBooleanStr[MB_Rec.MB7]); WriteLn; Gruß, Andreas |
AW: Record als Result einer Funktion
Zitat:
Delphi-Quellcode:
program Project652;
{$APPTYPE CONSOLE} uses System.SysUtils; Type MyBoolean = (boUndef, boFalse, boTrue); CONST MyBooleanStr: Array[MyBoolean] of String = ('Undefiniert', 'Nein', 'Ja'); procedure Test; var MB: MyBoolean; begin if (MB < boUndef) or (MB > boTrue) then Writeln('Range Error!') else WriteLn('MB: MyBooleanStr[MB] = ', MyBooleanStr[MB]); end; procedure Dummy; var B: Byte; begin B := Random(256); end; procedure RandomTest; var I: Integer; begin for I := 1 to 1000 do begin Dummy; Test; end; end; begin try RandomTest; except on E: Exception do Writeln(E.ClassName, ': ', E.Message); end; Readln; end. |
AW: Record als Result einer Funktion
Inzwischen bin auch ich etwas klüger geworden... :oops:
Delphi-Quellcode:
Andreas
Function Get_Record: MB_Record;
VAR MB_Rec_Neu: MB_Record; Begin // OHNE eigene Initialisierung: Result:= MB_Rec_Neu; End; ... MB_Rec:= Get_Record; // Himitsu hat recht: Das funktioniert NICHT mehr... // Das Funktions-Ergebnis kommt uninitialisiert vom Stack zurück WriteLn('MB_Rec.MB1 = ', MyBooleanStr[MB_Rec.MB1]); WriteLn('MB_Rec.MB2 = ', MyBooleanStr[MB_Rec.MB2]); WriteLn('MB_Rec.MB3 = ', MyBooleanStr[MB_Rec.MB3]); WriteLn('MB_Rec.MB4 = ', MyBooleanStr[MB_Rec.MB4]); WriteLn('MB_Rec.MB5 = ', MyBooleanStr[MB_Rec.MB5]); WriteLn('MB_Rec.MB6 = ', MyBooleanStr[MB_Rec.MB6]); WriteLn('MB_Rec.MB7 = ', MyBooleanStr[MB_Rec.MB7]); WriteLn; |
AW: Record als Result einer Funktion
Zitat:
Bei mir werden alle Werte nicht initialisiert, also undefiniert. Delphi 10.3.3 (VirtualBox unter Linux) |
AW: Record als Result einer Funktion
Zitat:
Der Fehler sitzt ein paar Zentimmer vor deinem Bildschirm, und wenn es in 2010 ging, dann auch drinnen. |
AW: Record als Result einer Funktion
Zitat:
Zentimmer Ich schreibe es mal richtig. Zitat:
Zitat:
Denn unter Delphi 10.3 und Up funktioniert es ja so wie es soll. Die Logik hinter dieser Aussage erschließt sich mir nicht. Zitat:
|
AW: Record als Result einer Funktion
Es ist nun mal so, dass verschiedene Delphi-Version für denselben Code unterschiedliche Hints und Warnings ausspucken. Ich habe schon häufig eine Variable initialisiert, obwohl das gar nicht notwendig war, damit der Compiler endlich Ruhe gibt, nur um dann bei einer neueren Delphi Version vom Compiler gesagt zu bekommen, dass die Zusweisung unnötig ist. Immerhin sind die Hints und Warnings der neueren Version häufiger korrekt als die der älteren.
|
AW: Record als Result einer Funktion
Zitat:
Ich schreibe meine Anwendungen Hints und Warnings frei. Und ja es ist mir bewusst das das x nicht initialisiert werden muss aber sage das mal dem alten Compiler von Delphi nochmals siehe "Solange wie Delphi es zulässt." Und Delphi lässt es nun mal nicht zu das man "Immer" alle Variablen initialisiert. De facto gibt es auch keine Faustregel dafür (unter Delphi) ![]() @dummzeuch Zitat:
Ja Herr himitsu es sind immer die Leute vor dem Bildschirm. :stupid: ohne geht es nun mal nicht. |
AW: Record als Result einer Funktion
Joar, irgendwer sitzt auch grade fett auf der Leitung, so langsam wie das hier ist.
Nja, dein Code lässt sich bei mir nichtmal kompiliere. :zwinker: Auf die schnell sah der Code daher auch bissl anders aus. Zitat:
falls FreePascal das im nicht-delphi-kompatiblen Modus das macht, dann naja. (dann da halt wie im C/C++) Aufgrund der länge hatte ich irgendwie etwas wie
Delphi-Quellcode:
oder
x := x + 1;
Delphi-Quellcode:
gesehn.
+ i
Dort kommt dann ohne das erste
Delphi-Quellcode:
natürlich zuerst der Fehler vonwegen nicht initialisiert.
x := 0;
So kommt in vielen Delphis bei Beidem
Delphi-Quellcode:
.
[dcc32 Hinweis] H2077 Auf 'x' zugewiesener Wert wird niemals benutzt
Bei Schleifen und IFs wird nicht beprüft ob und wieoft etwas ausgeführt wird. Nur da wo untypisierte Konstanten im IF vorkommen, und sich das durch die Codeoprimierung auf einen einzelnen Boolean kürzen lässt, da weiß dann der Compiler ob der nachfolgende Code im IF niemals ausgeführt wird und ignoriert ihn dann. (wegoptimiert diesen Codeteil) Also weiß der Compiler nicht, dass das
Delphi-Quellcode:
in der Schleife ausgeführt wird und somit auch nicht ob das vorherrige
X:=
Delphi-Quellcode:
überhaupt nicht nötig ist.
X:=
Delphi-Quellcode:
Aber sicher ist hier, dass die Zuweisungen definitiv niemals verwendet werden und seit Delphi 4 hat mich Delphi immer darauf hingewiesen, kann mich jedenfalls nicht erinnern, dass es mir mal nichts gesagt hätte.
var
x, i: Integer; begin x := 0; // [dcc32 Hinweis] H2077 Auf 'x' zugewiesener Wert wird niemals benutzt for i := 0 to 10 do //if i mod 2 then // [dcc32 Fehler] E2012 Ausdruckstyp muss BOOLEAN sein if i mod 2 <> 0 then x := i; // [dcc32 Hinweis] H2077 Auf 'x' zugewiesener Wert wird niemals benutzt //if x = 0 then ; end; |
AW: Record als Result einer Funktion
Zitat:
Zitat:
Desto-trotz. Unter Delphi 2010 meldet der Compiler das X nicht initialisiert wird. Darauf wollte ich hinaus. Für mich ist das Thema erledigt da es nun nicht mehr um das eigentliche Problem des TE geht. |
AW: Record als Result einer Funktion
Joar, vor allem da dort soein Bug eh nicht mehr behoben wird.
Manchmal ist auch einfach der Wurm drin. Im XE hatte ich letztens einen meiner geliebten Fatal Error mit zwei Leerzeichnen gebugfixt. (in 10.x wird er dann weg sein und ich kann die Leerzeichen dann wieder entfernen, falls ich's nicht vergesse :stupid:) |
AW: Record als Result einer Funktion
Zitat:
Ich würde ungern noch drei weitere Parameter über den Funktionsaufruf übergeben wollen. Generell habe ich eine Frage dazu: Automatisch erstellte Forms sind auch globale Variablen. Was ist der Unterschied zu einer in einer Unit gekapselten globalen Variable? LG Mathias |
AW: Record als Result einer Funktion
Zitat:
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 05:08 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz