Results 1 to 11 of 11

Thread: Return value of function might be undefined

  1. #1

    Return value of function might be undefined

    Hallo hallo,

    In een functie die geschreven heb, geef ik een record terug als result. Nu viel het me op dat ik geen warning krijg als ik vergeet een Result te zetten. Is dit normaal gedrag? Ik gebruikt 10.2.3 Pro.

    Onderstaande code geeft bij mij alleen een warning voor DoSomethingElse?
    Code:
    unit Unit2;
    
    interface
    
    uses
      Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
      Vcl.Controls, Vcl.Forms, Vcl.Dialogs;
    
    type
      TmyRecord= record
        MyName: string;
      end;
    
      TForm2 = class(TForm)
      private
        { Private declarations }
      public
        { Public declarations }
        function DoSomething: TMyRecord;
        function DoSomethingElse: Integer;
      end;
    
    var
      Form2: TForm2;
    
    implementation
    
    {$R *.dfm}
    
    { TForm2 }
    
    function TForm2.DoSomething: TMyRecord;
    begin
    
    end;
    
    function TForm2.DoSomethingElse: Integer;
    begin
    
    end;
    
    end.
    Bij voorbaat dank!

  2. #2
    Is het niet zo dat de compiler zelf intern de TMyRecord aanmaakt (en op nul stelt)?
    Dat zou betekenen dat je Result wel altijd een waarde heeft (n.l. sowieso een TMyRecord gevuld met nullen).

    En dan is je Result dus wel gedefinieerd.

    W1035 Return value of function '%s' might be undefined

  3. #3
    Is het niet zo dat de compiler zelf intern de TMyRecord aanmaakt (en op nul stelt)?
    Het kan zijn dat je gelijk hebt, maar op zich zou een warning wel op zijn plaats zijn naar mijn mening.

  4. #4
    Senior Member EricLang's Avatar
    Join Date
    May 2002
    Location
    Holland
    Posts
    3,023
    Bij mij gebeurt hetzelfde. Lijkt me inderdaad wel een warning waard!

  5. #5
    Fornicatorus Formicidae VideoRipper's Avatar
    Join Date
    Mar 2005
    Location
    Vicus Saltus Orientalem
    Posts
    5,251
    Het enige dat ik weet is dat een record nooit null of ongedefinieerd kán zijn, puur op basis van
    de eigenschappen van het record-type.

    Wat voor compilermagie erachter zit weet ik niet, maar in principe hebben de velden van een
    record in beginsel standaard lege waarden zoals dat ook bij klasse-variabelen van een klasse
    gaat (dus string = '', integer = 0, etc.).
    Vermoedelijk wordt er bij de aanroep van een functie expliciet een nieuw record (pointer)
    aangemaakt en met lege waarden gevuld, daar waar bij eenvoudige typen gewoon oude waarden
    (pointers) herbruikt worden (welke dus in potentie een verkeerde waarde kunnen hebben).

    Er komt bij een record als uitgang dus altijd een geldig en ingevuld record uit, ook al heb je
    dat zelf nooit gedaan.
    TMemoryLeak.Create(Nil);

  6. #6
    Senior Member EricLang's Avatar
    Join Date
    May 2002
    Location
    Holland
    Posts
    3,023
    Weten we echt heel zeker dat dat record op "niets" geinitialiseerd wordt in de functie?

  7. #7
    Fornicatorus Formicidae VideoRipper's Avatar
    Join Date
    Mar 2005
    Location
    Vicus Saltus Orientalem
    Posts
    5,251
    Enige manier om daar achter te komen is door het uit te proberen.

    Geen idee, ik gebruik bijna nooit records (bijna altijd alleen TObject afgeleiden) en als ik ze gebruik,
    dan zijn het constante arrays of record om een lijstje samen te stellen; ik gebruik ze in ieder geval
    nooit als uitgang van een functie (persoonlijke smaak, denk ik), juist omdat je nooit kunt weten of
    een method daadwerkelijk iets met zijn resultaat heeft kunnen doen (je kunt niet op TRUE of NIL
    testen na aanroep om te zien of het record verwerkt is).

    Zoals ik het dus zou doen:
    Delphi Code:
    1. type
    2.   TNameValueRec = record
    3.     Name: string;
    4.     Value: string;
    5.   end;
    6.  
    7. function SpitsNameValue(const S: string; out ANameValueRec: TNameValueRec): Boolean;
    8. var
    9.   P: Integer;
    10. begin
    11.   P := Pos('=', S);
    12.   Result := P > 0;
    13.   if Result then
    14.   begin
    15.     Result.Name := Copy(S, 1, Pred(P));
    16.     Result.Value := Copy(S, Succ(P), Length(S));
    17.   end;
    18. end;
    Last edited by VideoRipper; 23-Jul-18 at 09:40.
    TMemoryLeak.Create(Nil);

  8. #8
    Ik heb het getest. Ik had (tegen beter weten in) gehoopt dat de variabelen in het record geïnitializeerd zouden worden op 0, maar dat is niet het geval. Het zou dus alleen maar terecht zijn als je daar ook een waarschuwing op krijgt, maar dat gebeurt inderdaad niet.

    Strings zijn ook een vreemde eend in de bijt. Result is namelijk wel altijd een geldige string (inclusief ref-counting en alles), maar is niet noodzakelijk een lege string. Dat heb ik ook al eens pijnlijk ondervonden. Ook daar komt geen waarschuwing van. Nou is een integer met die toevallige waarde ook geldig, dus het is tamelijk arbitrair dat je voor de één wel een warning krijgt, en voor de ander niet.
    1+1=b

  9. #9
    mov rax,marcov; push rax marcov's Avatar
    Join Date
    Apr 2004
    Location
    Ehv, Nl
    Posts
    9,710
    Complexe functie resultaten ( array, record) gaan via een ander codegenerator traject (via de stack als impliciete VAR parameter) dan gewone functie resultaten die in registers (EAX/RAX of EDX:EAX resp RDX:RAX) teruggegeven worden.

    Dus waarschijnlijk is de warning gewoon niet geimplementeerd voor dat traject. FPC geeft wel een waarschuwing.

    Echter in het algemeen moet je warnings en hints met een korreltje zout nemen. Er zitten daar nogal wat fouten in in beide compilers. Beste is regelmatig met beide proberen, en nooit warnings definitief wegmoffelen (zodat je ze later altijd opnieuw kan testen, b.v. met een nieuwere versie)

    Mogelijk is de Delphi LLVM compiler er beter in, aangezien LLVM hier zeer uitgebreide functionaliteit heeft. Maar ja, moet Idera het wel goed implementeren.
    Last edited by marcov; 23-Jul-18 at 12:48.

  10. #10
    mov rax,marcov; push rax marcov's Avatar
    Join Date
    Apr 2004
    Location
    Ehv, Nl
    Posts
    9,710
    Quote Originally Posted by VideoRipper View Post
    Het enige dat ik weet is dat een record nooit null of ongedefinieerd kán zijn, puur op basis van
    de eigenschappen van het record-type.
    Alleen managed types worden door alle Delphi versies goed geinitializeerd. Sommige versies doen bij kleine records liever alles op 0 zetten ipv veld voor veld, maar dat is geen algemene regel of garantie.

    Je hoort dit soort dingen vaak, en het is niet correct. Vaak haspelt men testjes met records als globale variabelen of velden (die wel altijd geinitializeerd worden door elkaar. (en dat globale variabelen geinitializeerd worden is eigenlijk meer een PE-loader en dus windows feature, en niet echt de taal).

    Er op vertrouwen is gevaarlijk. En compiler gedrag aan de hand van warnings proberen te duiden is al helemaal gevaarlijk. De generatie en de flow analysis zijn deels gescheiden. (de generatie gebruikt soms resultaten van flow analysis, maar doet soms ook andere of additionele checks)

    Als je compiler gedrag wil vastleggen, dan moet je veel tests maken (en daar bij ook types en record grootte e.d. varieren, alsmede settings (optimalizatie, rtti, stackframes) ), en zo hard mogelijk checken wat er gebeurd (b.v. assembler inspectie)

  11. #11
    Fornicatorus Formicidae VideoRipper's Avatar
    Join Date
    Mar 2005
    Location
    Vicus Saltus Orientalem
    Posts
    5,251
    Quote Originally Posted by marcov View Post
    Complexe functie resultaten ( array, record) gaan via een ander codegenerator traject (via de stack als impliciete VAR parameter) dan gewone functie resultaten die in registers (EAX/RAX of EDX:EAX resp RDX:RAX) teruggegeven worden.
    Kijk, dat zijn de antwoorden die ik hoopte te krijgen.
    Het blijft voor mij voor een groot deel compiler magie, maar ik snap wel wat ongeveer de strekking is.
    TMemoryLeak.Create(Nil);

Thread Information

Users Browsing this Thread

There are currently 1 users browsing this thread. (0 members and 1 guests)

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •