2016-07-19 13 views
3

私はPascalScriptのinnosetupインストーラを使っています。次のブロックの制御がどこに流れているのか分かりません。Pascal(スクリプト)と例外制御フロー

function Foo(): String; 
begin 
    Result := 'foo'; 
    RaiseException('...'); 
end; 

procedure Test(); 
var 
    Z : String; 
begin 
    Z := ''; 
    try 
    Z := Foo(); 
    except 
    Log(Z); 
    end 
end; 

私のインストーラがZFoo機能のResultで設定されていることを示しているようです。私が「ほとんどの」プログラミング言語で例外を理解すると、例外の場合にはZ := Foo()という代入が行われてはならないことがわかります。

Foo関数が呼び出されたときには、Zはまだ割り当てられていますか?

+1

@MartinPrikryl:そうです。私は手書きの例とプロダクションコードを手に入れました。私はそれをコンパイルして実行しました。 – xtofl

答えて

2

おそらく、結果値を暗黙的な第1引数として参照によって扱います。しかし、これが起こる可能性があります。これは、コード生成/最適化の法則とみなすことができます。なぜなら、これは戻り値を処理する一般的な方法であるからです。

しかし、オブジェクトパスカルで定義されているのは、x86とx86_64の実装だけであるため、デルファイの動作が暗い領域ではないことです。そして、Delphiはeaxの値を返します。そのロジックに従えば、これは違法です。後で追加


をIは、構造化タイプとデルファイをテストし、それが基準を通過しながら、それを渡すためにスタックにコピーを作成します。

これは、構造化型でコードを最適化するのが難しくなる可能性がありますが、戻り値の型constを宣言するための修飾子/属性は必要に応じて修正できます。

+1

私はDelphiを構造化型でテストし、参照を渡している間にスタックにコピーを作成して渡します。だから、たとえDelphiが参照渡しされても、そのようなケースを守っても(パフォーマンスは犠牲になります) –

+0

「スタック上のコピー」とはどういう意味ですか?ここに「バグ」とは何ですか? –

+0

パスカルのバグ。複雑な/構造化された戻り値の場合、FPCとDelphiは戻り値の型と同じ型の一時変数を作成し、それを参照渡しします。関数を呼び出した後、その結果は最終目的地にコピーされます。パスカルスクリプト –

2

デルファイでは、結果の値としての文字列は、varのように扱われます。

procedure Foo(var Result: string); 
begin 
    Result := 'Foo'; 
    RaiseException(...); 
end; 

これはZ(参照パラメータを介して)は、直ちに値'Foo'が割り当てられ、すなわち前に例外が発生したことを意味する。換言すれば、Fooのような機能は、実際にコンパイルされます。

つまり、関数結果はResultというローカル変数に保持されず、関数が終了するときに返されます。例外によって防止されます。すぐに代入されます。

これは、PascalScriptでもまさにこれが起こっていると思います。

+0

関数は戻り値に何が起きるかを '知っています'?関数呼び出しは 'A:= Foo()'と 'A:= '...' + Foo()'をどのように区別しますか? – xtofl

+0

@xtofl: ''...' + Foo()'のため、到達できない中間文字列に書き込みます。中間の文字列が '' Foo''に設定されていると確信していますが、例外は完全な式の形成を妨げています。 IOW、それは:中間:= Foo();の後に 'A:= '...' +中間;'が続きます。 'intermediate'は例外の前に' 'Foo''に設定されていますが、それは例外の後にあるので完全な式は形成され続けることができません。また、「中間」は到達可能ではありません。つまり、コード内で明示的に参照されていません。 –

+0

したがって、 'A:= Foo()'の場合、中間文字列はありません - それは最適化かそれとも言語で定義されていますか? – xtofl