2009-03-28 6 views
6

私のプログラミング言語の授業では、言語デザインの歴史の中でいくつかの重要な人々がいくつかの論文を書いています。 CAR Hoareによるものが私を奇妙に思い知らされたのは、C言語で使われていた独立したコンパイル技法とC++がC言語に普及する前にC++で書かれていたことです。C#やJavaなどの言語は、独立したコンパイルのようにC/C++を避けるにはどうすればいいですか?

これは主にコンパイル時間を短縮するための最適化であるため、独立したコンパイルに依存しないようにするJavaとC#についてはどうでしょうか?それはコンパイラテクニックですか、これを容易にする言語要素がありますか?そしてそれらの前にこれらのテクニックを使った他のコンパイル言語はありますか?

答えて

5

短い答え:JavaとC#は別々のコンパイルを避けます。彼らはそれを十分に活用する。

再利用可能なライブラリを書くときに、別々のヘッダ/実装ファイルのペアをプログラマが書く必要がない点が異なります。ユーザーはクラスの定義を一度書きます。コンパイラはその単一の定義から "ヘッダー"に相当する情報を抽出し、出力ファイルに "タイプメタデータ"として含めます。そのため、出力ファイル(.jarはJavaで.classファイル、.NETベースの言語では.dllアセンブリ)は、単一パッケージ内のバイナリとヘッダーの組み合わせです。

別のクラスがコンパイルされ、それが第1クラスに依存する場合、別のインクルードファイルを探す必要がなく、メタデータを参照することができます。

特定のチップアーキテクチャではなく、仮想マシンをターゲットにしているようですが、これは別の問題です。 x86マシンコードをバイナリ形式にして、同じファイルにヘッダーのようなメタデータを残しておくこともできます(これはまれにしか使用されませんが、実際.NETのオプションです)。

C++コンパイラでは、 "コンパイル済みヘッダー"を使用してコンパイルを高速化しようとするのが一般的です。 .NETの.dll.classファイルのメタデータは、あらかじめコンパイルされたヘッダーによく似ています。すでに解析され、索引付けされているため、迅速な検索が可能です。

これらの現代語では、モジュール化を行う方法が1つあり、完全に体系化され手作業で最適化されたC++モジュラービルドシステムの特徴を持っています.- ASFAC++B

4

ここで最も大きな要因の1つは、Javaと.NETの両方で中間言語が使用されていることです。つまり、コンパイルされたユニット(jar/assembly)には、タイプ、メソッドなどに関する多くの表現可能なメタデータが前提条件として含まれています。参照検査のために既に便利にレイアウトされていることを意味します。あなたが高速なものを引っ張っている場合には、実行時にはまだチェックされています; -p

これはCOMを支えるMIDLからはあまり離れていませんが、TLBはしばしば別のエンティティです。特に

私はあなたの意味を誤解している場合、私は...

+0

私はあなたが私を正しく理解したと信じています。私は基本的にC/C++のアイデアを意味しています。各ソースファイルはそれぞれのコンパイル単位です。これは、C#やJavaの場合とほとんど変わりません。 –

2

を教えてくださいそれはいくつかの言語のサポートを必要とする(そうでない場合は、C/C++コンパイラはあまりにもそれを行うだろう)

、それがあることが必要ですコンパイラは自己完結型のモジュールを生成します。自己完結型のモジュールは、他のモジュールがそれらを呼び出すために参照できるメタデータを公開します。

.NETアセンブリは簡単な例です。プロジェクト内のすべてのファイルが一緒にコンパイルされ、1つのdllが生成されます。このdllは.NETに照会して、その型に含まれる型を判別し、他のアセンブリで定義されている関数を呼び出すことができます。

これを利用するには、他のモジュールを参照することが言語上合法でなければなりません。

C++では、モジュールの境界をどのように定義しますか?言語は、コンパイラが現在のコンパイル単位(.cppファイル+インクルードヘッダー)内のデータのみを考慮することを指定します。 「コンパイル時にプロトタイプや何も持っていないのに、関数Fooをモジュールバーで呼びたい」と指定する仕組みはありません。ファイル間で型情報を共有するための唯一のメカニズムは#includeです。

C++にモジュールシステムを追加する提案がありますが、C++ 0xには含まれません。私が最後に見たのは、0x1が出てからTR1のためにそれを検討するという計画でした。

(それはコンパイルをスピードをアップいただきたいので、C/C++での#includeシステムが最初に使用されたことを言及する価値があります。戻る70年代に、それはコンパイラは、単純な線形スキャンでコードを処理することができました。これ構文木などの「高度な」機能を構築する必要はありませんでしたが、今日ではテーブルが回転しており、使いやすさとコンパイル速度の両面で大きなボトルネックになっています)。

+0

C言語の設計は、メモリが限られたマシンではコンパイルが高速になるようにしようとするよりも、コンパイルが確実になるようにしました。今日では、ソースコード全体が一般的なデスクトップマシンのRAMに簡単に収まらないシステムは比較的少数ですが、Cは大規模なマシンが今日の日常的な1/16,000以下のRAMを持つ時代に設計されましたワークステーション。開発環境では、ビルド速度と実用的なビルド・サイズの間で厳しいトレードオフが必要でした。 – supercat

2

C/C++はコンパイラではなく、リンカによってのみ読み込まれるようになっています。

1

その他の言語について:IIRC Turbo Pascalには、ソースコードなしで使用できる「単位」がありました。私は、コンパイルされたコードとともにメタデータを作成し、それをコンパイラがモジュールへのインターフェイス(すなわち、関数のシグネチャ、クラスレイアウトなど)を理解するために使用できると考えています。)

#includeを#importに置き換えることを防ぐC/C++の問題は、インクルード/インポートされたモジュールの意味/構文などを完全に変更できるプリプロセッサでもあります。これは、Javaのようなモジュールシステムでは(不可能ではないにしても)非常に困難です。

3

java .classファイルはC/C++のプリコンパイル済みヘッダーファイルと似ていると考えることができます。本質的に.classファイルは、C/C++リンカが必要とする中間形式であり、ヘッダに含まれるすべての情報(Javaには別個のヘッダがありません)です。

別のポストにコメントフォーム:。

「私は基本的に意味していた各ソースファイルは、独自の 個々のコンパイル単位であることを++ C/Cでのアイデアこの がするほどではないように見えるが C#またはJavaの場合です。

Java(私はC#では話せませんが、同じと仮定しますが)それぞれのソースファイルは、それぞれのコンパイル単位です。どうしてあなたがそうではないと思うのか分かりません...おそらく、私たちは編集単位の定義が異なっていますか?

関連する問題