2015-09-16 1 views
5

なぜこのコードはコンパイラエラーになりませんか?私は、例えば "CallMe"へのあいまいな呼び出しのようなエラーが予想されます。これはコンパイラや言語のバグですか?これは、関数名の前にユニット名とドットを使用することで回避できますが、名前の衝突に対してユーザーコードとライブラリコードを保護しません。あなたのコードは何かをしたが、それは他の何かをしたと思う、それは悪いです。異なるユニットで同じシグネチャを持つ関数を呼び出すと、コンパイラエラーが発生するのはなぜですか?

uses 
    Unit2, Unit3; 

{$R *.lfm} 
{ TForm1 } 
procedure TForm1.Button1Click(Sender: TObject); 
begin 
    ShowMessage(IntToStr(CallMe(5))); 
end; 

unit Unit2; 
{$mode objfpc}{$H+} 
interface 
uses 
    Classes, SysUtils; 
function CallMe(A: Integer) : Integer; 
implementation 
function CallMe(A: Integer) : Integer; 
begin 
    Result := A * 2; 
end; 
end. 

unit Unit3; 
{$mode objfpc}{$H+} 
interface 
uses 
    Classes, SysUtils; 
function CallMe(A: Integer) : Integer; 
implementation 
function CallMe(A: Integer) : Integer; 
begin 
    Result := A * -1; 
end; 
end. 
+5

これは仕様です。コンパイラが最後にコンパイルしたものをコンパイル時に呼び出します。他のものを呼びたい場合は、ユニット名の前にドットをつけて名前に付けてください。 – MartynA

+0

ありがとうございます。私はこのデザインの背後にある動機づけを知りたいです。これはバグの機会を作ります。ユニット2のCallMeを元々使用していたプログラマBがユニット3を追加したとしましょう。彼は誤ってCallMeを何か他のものに置き換えたことを知らないので(unit of code)コンパイルして実行します。警告なしエラーなし。私はむしろ実行時の問題よりもコンパイラエラーがあり、私はAVeryLongLibraryName.FunctionNameコールを必要とせず、曖昧な呼び出しのためにすべてのインクルードユニットですべての呼び出しを調べる必要はありません。 –

+1

プログラミング言語はバグの可能性を秘めています。すべては、あなたが何をしているのかを知る必要があります。これらのケースについてのヒントを示す外部ツールがあります。 –

答えて

13
documentation

より:

二つのユニットが同じ名前を持つ変数、定数、タイプ、プロシージャ、または関数を宣言すると、コンパイラはuses節に記載されている最後のユニットから1つを使用します。

+0

私は参照してください。私はこれが非常に驚くべきことであり、私の意見は危険な行動であると言わなければならない。プロジェクトに後で追加されたライブラリには、古いコードと同じシグネチャを持つ関数があり、新しいコードがuses節で最後に追加され、新しい関数にバグがあり、別の方法で働いたため、古い関数が新しい関数を使用し始めました。トラブルを引き起こした。これはオプションでコンパイルエラーに変えることができるのですか?これは偶然によって再び発生しませんか? –

+0

私はTP4日以来この行動をしてきましたが、実際に名前の衝突に何の問題もありませんでした。この状態を示すヒント/警告/エラーオプションはありません。コードの洞察は助けになるかもしれません、機能が属しているユニットを示す。 –

+0

@ user2304430:エラーではないので、エラーにする方法はありません。 –

2

コンパイラは、意図的に、スタックベースのアプローチを使用してユニットからシンボルをロードし、パーズします(これは、ユニットの識別子にアクセスするために使用されます)。最後にロードされたものから最初にロードされたものまでのスタックを通して、シンボルを検索する。プリプロセッサの状態はグローバルな状態に直接マージされます。

クロスユニットのオーバーロードは例外です。両方の機能をの過負荷でマークすると、ディレクティブは、あなたは二つの異なる署名を持っている場合、それは1に一致する最善を選択します

[dcc32 Error] test.dpr: E2251 Ambiguous overloaded call to 'bla' 
    Unit1.pas(8): Related method: procedure bla; 
    Unit2.pas(8): Related method: procedure bla; 

(BLAは、テスト中の関数の名前だった)エラーが発生します。

クロスオーバーロードは新しい機能ですが、正確なタイミングはわかりません。私の推測はD2006です。

関連する問題