2015-06-07 15 views
10

Vorsicht vor Exit Befehl Verwendung in Inline-Funktionen! Ich habe Delphi XE3 hier benutzt.Ist es ein Fehler, der versucht, diesen Code zu kompilieren, führt dazu, dass die IDE beendet wird oder der Compiler nicht ausgeführt werden kann?

Symptom

Unter bestimmten Umständen, wenn ein Anruf zu einer Inline-Funktion hergestellt ist, die Exit Befehl enthält, und den Rückgabewert der Inline-Funktion direkt in WriteLn() verwendet wird, meldet der Compiler einen Fehler Nachricht,

oder sogar am schlimmsten, die Delphi-IDE endet ohne Bestätigung.

function ProcessNumber(const iNumber: Integer): Boolean; inline; 
begin 
    if iNumber = 0 then begin 
    Result := False; 
    Exit; 
    end; 
    // some code here ... 
    Result := True; 
end; 

procedure Test; 
begin 
    writeln(ProcessNumber(0)); 
end; 

begin 
    Test; 
    ReadLn; 
end. 

Wenn jedoch der Rückgabewert der Inline-Funktion in einer Variable gespeichert wird, und dann wird die Variable in WriteLn() verwendet, ist das Problem nicht auftritt.

procedure Test; 
var 
    b: Boolean; 
begin 
    b := ProcessNumber(0); 
    writeln(b); 
end; 

Fragen

  1. Ist das ein Compiler Fehler?
  2. Wenn dies ein Fehler ist, gibt es eine Problemumgehung zum sicheren Beenden einer Inline-Funktion?
+0

Es frage ich mich macht, erwarten Sie diese den Anrufer Kontext zu verlassen, oder einfach nur die Inline-Funktion? – TLama

+0

@TLama Ich glaube, der Fragesteller weiß, dass 'inline' nicht ändert, was' exit' bedeutet.Es ist das interne AV, das die IDE tötet, die das Problem ist. –

Antwort

10

Dies ist sicherlich ein Fehler. Es tritt in allen IDE-Versionen auf, die ich getestet habe, XE3, XE7 und XE8. Ich glaube ehrlich gesagt nicht, dass du viel kannst. Für mich endet die IDE jedes Mal mit der Kompilierung. Ich denke, Sie müssen den Code nur so schreiben, dass er nicht zu IDE-Abstürzen führt.

Sie können die IDE-Option verwenden, die die Kompilierung zur Verwendung von msbuild erzwingt. Dies versetzt die Kompilierung in einen separaten Prozess und stellt so sicher, dass die IDE nicht abstürzt. Es wird Ihnen nicht viel helfen, denn obwohl Ihre IDE nicht weiter sterben wird, können Sie Ihr Programm nicht kompilieren!

Wenn Sie mit msbuild bauen, erhalten Sie einen Fehler dieser Form erhalten:

error F2084: Internal Error: GPFC00000FD-004D3F34-0

Der GPF steht für allgemeine Schutzverletzung, das ist eine Speicherzugriffsverletzung. Dies ist vermutlich eine unbehandelte Ausnahme, die die IDE zerstört, wenn die Kompilierung im Prozess ausgeführt wird.

Mein Rat ist, dass Sie einen Fehlerbericht an Quality Portal senden. Nur so kann der Defekt behoben werden. Erwarten Sie jedoch nicht, dass jemals ein Update zu XE3 kommt.

+0

Heffernan, danke für die Antwort. Ich habe [den Fehler] (https://quality.embarcadero.com/browse/AP-165) beim Quality Portal eingereicht. Ich denke, ich bin gezwungen, 'goto' * labelExit * als Workaround zu verwenden. – Astaroth

+0

@Astaroth - aussteigen ist nicht immer ein Problem. Dies scheint in Ordnung zu sein. Ergebnis: = iNumber <> 0; wenn nicht Ergebnis, dann Beenden; ... –

2

Eine Problemumgehung, die Sie hier verwenden können, besteht darin, die bedingte if-Implementierung umzukehren und somit die Verwendung des Befehls Beenden insgesamt zu vermeiden.

So anstelle von

function ProcessNumber(const iNumber: Integer): Boolean; inline; 
begin 
    if iNumber = 0 then begin 
    Result := False; 
    Exit; 
    end; 
    // some code here ... 
    Result := True; 
end; 

Verwendung

function ProcessNumber(const iNumber: Integer): Boolean; inline; 
begin 
    if iNumber <> 0 then begin 
    // some code here 
    Result := True; 
    end; 
    else 
    Result := False; 
    //No exit needed here as this is already at the end of your method 
end; 
+1

SilverWarior, ich schätze deinen Kommentar, also +1 von mir. In meinem Beispiel zeige ich jedoch nur, dass sich der Befehl 'Exit' unter bestimmten Umständen unerwartet verhält. Mein Beispiel spiegelt meine tatsächliche Codestruktur nicht wirklich wider. Ich bin mir sicher, dass jeder Entwickler jemals eine Situation erlebt hat, in der "Exit" unmittelbar von einer Funktion die beste verfügbare Option in Bezug auf Effizienz ist. Jedenfalls stimme ich Ihnen zu, dass manchmal (wie in meinem Beispiel) das Vermeiden des 'Exit'-Befehls die Code-Leistung nicht verringert. – Astaroth

+0

Ich hatte den Verdacht, dass die Lösung nicht so einfach sein kann, aber trotzdem würden Sie nicht glauben, wie oft Sie selbst einfachste Lösungen übersehen können. Vor allem, wenn Sie einige Zeit damit verbringen, sich über ein Problem zu ärgern und zu vergessen, das große Ganze zu betrachten und zu versuchen, dieses Problem vielleicht zu vermeiden. – SilverWarior

+0

@Silver Der reale Code ist wahrscheinlich größer und die Vermeidung von Exit würde die Funktion weniger klar machen. –