1

ヘッダーとヘッダー ガードについて理解できません。他の質問とその回答を読みましたが、Visual Studio 2013 でこれを機能させることはできません:

main.cpp

#include "stdafx.h"
#include <iostream>
#include "add.h"

int _tmain(int argc, _TCHAR* argv[]) {
    std::cout << "3 + 4 = " << add(3, 4) << std::endl;
    system("pause");
    return 0;
}

add.cpp

#include "stdafx.h" //ADDED LATER; NOW WORKING (AND SEE QUESTION 2 BELOW)
#include "add.h" //ADDED LATER; NOR WORKING (AND SEE QUESTION 2 BELOW)
int add(int x, int y) {
    return x + y;
}

add.h

#ifndef ADD_H
#define ADD_H
int add(int x, int y);
#endif

コンパイルすると、コンソール ウィンドウが画面上で点滅してから消えます。エラー リストには次のものが含まれます。

エラー 1 エラー LNK2019: 未解決の外部シンボル "int __cdecl add(int,int)" (?add@@YAHHH@Z) が関数 _wmain で参照されています c:\Users\Danny\documents\visual studio 2013\Projects\Addition Program\main \main.obj メイン

エラー 2 エラー LNK1120: 1 未解決の外部 c:\users\danny\documents\visual studio 2013\Projects\Addition Program\Debug\main.exe メイン


1. ヘッダーとヘッダー ガードはどのように機能しますか? #include によっての宣言を認識するadd.h方法がわかりますが、その定義をどのように見つけるのでしょうか?main.cppadd(int x, int y)


2. コードのどこが間違っていますか?

私のコードは現在コンパイル中です。コードがコンパイルされなかった理由は、Visual Studioのソリューション エクスプローラーの [ソースファイル]セクションと[ヘッダー ファイル]セクションからファイルを追加するのではなく、[ファイル] > [新規] > [ファイル... ] に移動してプロジェクトにファイルを追加していたためです。add.cpp ファイルにも追加する必要がありました。#include "stdafx.h

4

2 に答える 2

5

このように考えてみてください。各.cppファイルは前処理されてから、他のファイルとは完全に個別にコンパイルされます。

それでは、まず前処理をしましょうmain.cpp。これには、 で始まるすべての行を調べる必要があり#ます。ファイルmain.cppには行しかなく#include、含まれているファイルの内容を単純にコピーします。stdafx.handの内容をコメントで表しiostreamますが、実際には in の内容をコピーしますadd.h

// Contents of stdafx.h
// Contents of iostream
#ifndef ADD_H
#define ADD_H
int add(int x, int y);
#endif

int _tmain(int argc, _TCHAR* argv[]) {
    std::cout << "3 + 4 = " << add(3, 4) << std::endl;
    system("pause");
    return 0;
}

の内容がadd.hに取り込まれたことを確認してmain.cppください。そして、たまたま、これによりさらにいくつかのプリプロセッサ ディレクティブが導入されたので、それらの指示に従う必要があります。ADD_H最初は が (このファイルで) まだ定義されていないかどうかをチェックし#endifます。

// Contents of stdafx.h
// Contents of iostream
#define ADD_H
int add(int x, int y);

int _tmain(int argc, _TCHAR* argv[]) {
    std::cout << "3 + 4 = " << add(3, 4) << std::endl;
    system("pause");
    return 0;
}

残りのプリプロセッサ ディレクティブが定義ADD_Hされ、最終的な翻訳単位が残ります。

// Contents of stdafx.h
// Contents of iostream
int add(int x, int y);

int _tmain(int argc, _TCHAR* argv[]) {
    std::cout << "3 + 4 = " << add(3, 4) << std::endl;
    system("pause");
    return 0;
}

これで、このファイルをコンパイルできます。のような関数を呼び出す場合add、コンパイラはその関数の宣言を確認できれば、正常にコンパイルできます。関数は他の翻訳単位で定義されることが予想されます。

それでは、前処理を見てみましょうadd.cpp。実際にadd.cppは、前処理ディレクティブがないため、何もする必要はありません。通常はそうしますが#include "add.h"、そうしなくてもプログラムはコンパイルされます。したがって、前処理後も次のようになります。

int add(int x, int y) {
    return x + y;
}

これがコンパイルされ、add関数の定義ができました。

すべての.cppファイルがコンパイルされた後、リンクされます。リンカーは、コンパイルされmain.cppた関数が関数を使用していることを確認する責任があるaddため、その定義を探します。コンパイルされた定義を見つけて、add.cppそれらをリンクします。


なぜガードを含めたのか疑問に思うかもしれません。この例では、かなり価値がないように見えました。そうです、この例では実際には何の役にも立ちませんでした。インクルード ガードは、同じヘッダーが 1 つのファイルに 2 回インクルードされるのを防ぐためにあります。これは、プロジェクト構造がより複雑な場合に簡単に発生する可能性があります。ただし、 2 回main.cppインクルードする非現実的な例を見てみましょう。add.h

#include "stdafx.h"
#include <iostream>
#include "add.h"
#include "add.h"

int _tmain(int argc, _TCHAR* argv[]) {
    std::cout << "3 + 4 = " << add(3, 4) << std::endl;
    system("pause");
    return 0;
}

これを前処理すると、次のようになります。

// Contents of stdafx.h
// Contents of iostream
#ifndef ADD_H
#define ADD_H
int add(int x, int y);
#endif
#ifndef ADD_H
#define ADD_H
int add(int x, int y);
#endif

int _tmain(int argc, _TCHAR* argv[]) {
    std::cout << "3 + 4 = " << add(3, 4) << std::endl;
    system("pause");
    return 0;
}

最初#ifndefはプロセスであり、それがADD_Hまだ定義されていないことがわかり、それまでのすべて#endifが残ります。これにより、 が定義されますADD_H

次に 2 番目#ifndefが処理されますが、この時点でADD_Hが定義されているため、 まではすべて#endif破棄されます。

関数 (および他の多くのもの) の定義が複数あるとエラーが発生するため、これは非常に重要です。

于 2014-01-31T19:13:05.850 に答える
1

IDE は、各 .cpp ファイルを順番にコンパイルして、その特定のファイルのオブジェクト ファイル (マシン コード) を生成します。

これがすべて完了すると、ビットを書き込んで実行可能ファイルを形成します。IDE は、何を何にリンクする必要があるかを認識しています。

これは少し単純な答えです

于 2014-01-31T19:05:14.050 に答える