4

一般的に言えば、ac/c++ コンパイラがどのように機能するのかまったくわからないことに最近気づきました。これは当初、ヘッダー ガードを理解しようとしていたことを認めますが、コンパイルのしくみが不足していることに気づきました。

たとえば、Visual C++ を取り上げます。「Header Files」フォルダ、「Resources Files」フォルダ、「Source Files」フォルダがあります。これらのフォルダーを分離し、そこに何を入れることに何か意味はありますか? 私にとって、それらはすべてソース ファイルです。コード スニペットを見てみましょう。

スニペット 1

//a1.h
int r=4;

//a1.cpp
int b  //<--semicolon left out on purpose

//main.cpp
#include <iostream>
#include "a1.h"
void main()
{
   cout << r;
}

コンパイラは、「a1.cpp(3) : 致命的なエラー C1004: 予期しないファイルの終わりが見つかりました」と言ってエラーを出します。次のコード スニペット

スニペット 2

//a1.h
int r=4 //<--semicolon left out on purpose

//a1.cpp
int b = 4;  

//main.cpp
#include <iostream>
void main()
{
   cout << b;
}

「main.cpp(6) : エラー C2065: 'b' : 宣言されていない識別子」のため、エラーが発生します。a1.cpp をそのように含めると

スニペット 3

//a1.h
int r=4 //<--semicolon left out on purpose

//a1.cpp
int b = 4;  

//main.cpp
#include <iostream>
#include "a1.cpp"
void main()
{
   cout << b;
}

コンパイラは、「a1.obj : エラー LNK2005: "int b" (?b@@3HA) は main.obj で既に定義されています」と不平を言います。スニペット 2 と 3 は両方ともint r = 4、セミコロンが欠落していないという事実を無視しています。これは、xxxx.h ファイルと関係があると思われるためです。スニペット 1 のプロジェクトから a1.cpp ファイルを削除すると、正常にコンパイルされます。明らかに、私が期待していたものは、私が得ているものではありません。cpp でコーディングする方法に関する本やチュートリアルはたくさんありますが、コンパイル プロセスで cpp がファイルやソース コードを処理する方法についてはあまり詳しくありません。ここで何が起こっているのですか?

4

7 に答える 7

6

あなたの質問は実際にはコンパイラに関するものではなく、IDE がビルド システム全体をどのように処理しているかに関するものです。ほとんどの C/C++ プロジェクトのビルド システムは、各ファイル.cまたは.cppファイルを個別にコンパイルし、結果のオブジェクト ファイルをリンクして最終的な実行可能ファイルにします。あなたの場合、IDE は、プロジェクト内にファイル名拡張子が付いたファイルをコンパイルし.cpp、結果のオブジェクトをリンクしています。表示されている動作は、次のように説明できます。

  1. a1.cppが欠落している;ため、IDE がそのファイルをコンパイルしようとすると、「予期しないファイルの終わり」に関するエラーが発生します。

  2. bmain.cppコンパイル単位のどこにも宣言されていないため、未定義の識別子に関するエラーが発生します。

  3. bmain.cppとの両方のa1.cppコンパイル ユニットに存在します (明らかに、およびfora1.cppを介して)。IDE はこれらのファイルの両方をコンパイルします。現在、それぞれに というオブジェクトが含まれています。リンクすると、シンボルの重複エラーが発生します。#includemain.cppa1.omain.ob

ここで取り上げる重要なポイントは、表示されるすべての動作を説明するものですが、IDE がすべて .cppのファイルをコンパイルmain.cppすることです。

自分で作成した makefile を使用してコマンド ライン テスト プロジェクトをセットアップすることをお勧めします。これにより、ビルド システムの内部動作がすべてわかり、その知識を IDE の内部動作に適用できます。

于 2011-03-17T17:20:44.220 に答える
3
  1. ヘッダファイルはコンパイルされません
  2. #include ディレクティブは、 #include 行の代わりに、インクルード可能なファイルの内容を文字通り貼り付けます
  3. すべてのソース ファイル (メインの redargless) は、.o または .obj ファイルにコンパイルされます。
  4. すべての obj ファイルは、外部の .lib ファイルがあれば一緒にリンクされます。
  5. 実行可能ファイルを取得します。

ポイント2について:

example
//a.h
int

//b.h
x = 

//c.h
5

//main.cpp
#include <iostream>
int main()
{
#include "a.h"
#include "b.h"
#include "c.h"
;

std::cout << x << std::endl; //prints 5 :) 
}

これは完全な答えではありませんが、hth、my2c など:)

于 2011-03-17T17:18:06.190 に答える
2

ご質問の理解には2通りあるようですので、C++コンパイルの理解部分についてお答えします。

ウィキペディアの「コンパイラ」の定義を読むことから始めることをお勧めします。その後、Google でコンパイラ チュートリアルを検索して、コンパイラに関する理解を深めてください。C++ に特化したものとして、about および preprocessor ディレクティブを読むことができます#include(これらの用語を Google 検索してみてください)。

コンパイラをさらに理解したい場合は、コンパイラの本をお勧めします。StackOverflow で適切な書籍のリストを見つけることができます。

于 2011-03-17T18:18:23.187 に答える
1

コンパイルするファイルをビルドシステムに指示します。Visual C ++の場合、プロジェクトに追加した「*.cpp」という名前のファイルが自動的にコンパイルされます。プロジェクト設定に移動して、そうしないように指示することはできますが。

* .hという名前のファイルはコンパイルされません(ただし、明示的に指示した場合はコンパイルできます)。

#includeディレクティブは、コンパイラーがコンパイルを実行するに処理するものです(プリプロセッサーと呼ばれます)。基本的に、それが指しているファイルを取得し、#includeディレクティブがファイルに表示された時点でコンパイルされているソースファイルに貼り付けます。次に、コンパイラーはそのすべてを1つの完全なユニットとしてコンパイルします。

したがって、例の場合:

スニペット1

Bote a1.cppとmain.cppは、ビルドシステムによって別々にコンパイルされます。したがって、エラーom a1.cppが発生すると、それが報告されます。

スニペット2

これらのファイルは相互に認識せずに別々にコンパイルされるため、main.cppでbを参照する場合、bがa1.cppで定義されていることを認識しないことに注意してください。

スニペット3

これで、main.cppにa1.cppが含まれているので、main.cppをコンパイルし、bの定義を確認して、「OK私はグローバルスコープでabを持っています」と言います。次に、a1.cppをコンパイルし、「OK」と表示します。グローバルスコープにabがあります。

これで、リンカーがステップインし、a1とmainを一緒にしようとします。これで、2つのbがグローバルスコープを食べたことがわかります。ダメ。

于 2011-03-17T17:31:06.587 に答える
1

#include ステートメントは、#include を作成するファイルにそのファイルを挿入します。したがって、スニペット 3 main.cpp はコンパイル前に次のようになります。

    // main.cpp    
    // All sorts of stuff from iostream
    //a1.cpp
    int b = 4;
    void main()
    {
        cout << b;
    }

リンカー エラーが発生する理由は、b を 2 回定義しているためです。a.cpp と main.cpp で定義されています。

宣言と定義について読みたいと思うかもしれません。

于 2011-03-17T17:25:47.737 に答える
0

コンパイラは、指定した場所からソース ファイルを取得します。Visual C++ の場合、コンパイラに何をすべきかを伝える IDE があり、さまざまなフォルダーが存在します。これは、IDE がそのようにファイルを編成するためです。

また、スニペット 2 のエラーは、コンパイラからではなく、リンカーからのものです。コンパイラは main.cpp と a1.cpp をオブジェクト ファイル main.obj と a1.obj にコンパイルし、リンカーはこれらのオブジェクト ファイルを組み合わせて実行可能ファイルを作成しようとしていますが、変数 b は a1.obj (直接) と a1.obj の両方にあります。 (a1.cpp のインクルードを介して) main.obj を使用しているため、「既に定義されています」というエラーが発生します。

于 2011-03-17T17:22:48.167 に答える
0

ケース 1 と 3 で見られる問題は、VS 固有のものです。VS は明らかに main.cpp と a1.cpp の両方をコンパイルしようとします。

ケース 1: VS が構文エラー (セミコロンがない) がある a1.cpp をコンパイルしようとすると、コンパイルが失敗します。

bケース 2: main.cpp またはインクルード ファイルで変数を宣言していません。したがって、コンパイルは失敗します。

ケース 3: これはリンカー エラーです。インクルードによりint b、a1.cpp と同様に main.cpp で宣言されています。それらのいずれも static または extern ではないため、同じ識別子を持つ 2 つのグローバル変数が同じスコープで宣言されています。これは許可されていません。

于 2011-03-17T17:27:20.597 に答える