16

私は、宣言と定義に2つのメソッドを使用している人々を見てきchar *ました。

Medhod 1:ヘッダーファイルには以下があります

extern const char* COUNTRY_NAME_USA = "USA";

Medhod 2:
ヘッダーファイルには次の宣言があります。

extern const char* COUNTRY_NAME_USA;

cppファイルの定義は次のとおりです。

extern const char* COUNTRY_NAME_USA = "USA";
  1. 方法1は何らかの形で間違っていますか?
  2. 2つの違いは何ですか?
  3. const char * const var「 」と「」の違いがわかりconst char * varます。上記のメソッドでconst char * const var、メソッド1のようにヘッダーで「」が宣言および定義されている場合、それは意味がありますか?
4

3 に答える 3

33

最初の方法は、ヘッダー ファイルで外部リンケージを持つオブジェクトの定義を作成するため、実際には間違っています。そのヘッダー ファイルが複数の翻訳単位に含まれると、One Definition Rule (ODR) に違反します。コードはコンパイルに失敗します (より正確には、リンクに失敗します)。COUNTRY_NAME_USA

2 番目の方法が正しい方法です。ただし、キーワードexternは定義ではオプションです。つまり、cppファイルでは実行できます

const char* COUNTRY_NAME_USA = "USA"

ヘッダー ファイルからの宣言が、この翻訳単位のこの定義の前にあると仮定します。

また、オブジェクト名が大文字であるため、おそらく定数になることを意図していると思います。その場合は、次のように宣言/定義する必要がありますconst char* const COUNTRY_NAME_USA(extra に注意してくださいconst)。

最後に、最後の詳細を考慮して、定数を次のように定義できます。

const char* const COUNTRY_NAME_USA = "USA"; // no `extern`!

ヘッダーファイルで。現在は定数であるため、デフォルトで内部リンケージがあります。つまり、ヘッダー ファイルが複数の翻訳単位に含まれていても、ODR 違反はありません。この場合COUNTRY_NAME_USA、各翻訳単位で個別の左辺値を取得します (一方、externメソッドではプログラム全体に対して 1 つを取得します)。あなたの場合に何が必要かは、あなただけが知っています。

于 2010-05-21T05:59:32.520 に答える
10

ポイントは何ですか?

文字列を検索したい場合 (ローカライズ可能)、これが最適です:

namespace CountryNames {
    const char* const US = "USA";
};

ポインターは const であるため、内部リンケージがあり、複数の定義が発生しません。ほとんどのリンカーは冗長な定数も結合するため、実行可能ファイルのスペースを無駄にすることはありません。

ただし、ポインターの等価性によって文字列を比較したい場合は、リンカーが定数折りたたみの最適化を実行する場合にのみポインターが等しくなるため、上記は移植性がありません。その場合、ヘッダー ファイルで extern ポインターを宣言するのがよい方法です (また、再ターゲットするつもりがない場合は、const にする必要があります)。

于 2010-05-21T04:38:25.297 に答える
5

グローバル変数が必要な場合は、.h ファイルで宣言し、1 つの (そして 1 つのみの) .cpp ファイルで定義するのが通常の方法です。

.h ファイル。

extern int x;

.cpp ファイル。

int x=3;

問題の本質は変数の型に依存しないため、例のように const char * ではなく int (おそらく最も基本的な基本型?) を使用しました。

基本的な考え方は、変数を複数回宣言できるということです。したがって、.h ファイルを含む各 .cpp ファイルで変数を宣言します。これで問題ありません。ただし、一度だけ定義します。定義は、変数の初期値 (= を使用) を割り当てるステートメントです。.h ファイルに定義を含める必要はありません。.h ファイルが複数の .cpp ファイルに含まれていると、複数の定義が得られるからです。1 つの変数に複数の定義がある場合、リンク時に問題が発生します。これは、リンカが変数のアドレスを割り当てたいのに、その変数のコピーが複数ある場合には適切に割り当てることができないためです。

Sud の混乱を和らげるために、後で追加された追加情報。

問題をよりよく理解するために、問題を最小限の部分に減らしてみてください。

3 つの .cpp ファイルで構成されるプログラムがあるとします。プログラムをビルドするには、各 .cpp を個別にコンパイルして 3 つのオブジェクト ファイルを作成し、次に 3 つのオブジェクト ファイルをリンクします。3 つの .cpp ファイルが次のような場合 (例 A、適切な構成)。

file1.cpp

extern int x;

file2.cpp

extern int x;

file3.cpp

extern int x;

その後、ファイルは問題なくコンパイルおよびリンクされます (少なくとも変数 x に関する限り)。各ファイルは変数 x を宣言しているだけなので問題ありません。宣言とは、使用できる (または使用できない) 変数がどこかにあることを示すだけです。

同じことを達成するためのより良い方法は次のとおりです (例 A、より良い構成)。

header.h

extern int x;

file1.cpp

#include "header.h"

file2.cpp

#include "header.h"

file3.cpp

#include "header.h"

#include ディレクティブは単純に別のファイルからテキストをプルするため、コンパイラは .cpp ファイル (または専門家が呼ぶ翻訳単位) を処理する際に、3 つのコンパイルのそれぞれで以前と同じテキストを認識します。 . それにもかかわらず、宣言が複数のファイルではなく 1 つのファイルにしかないため、これは以前の例よりも改善されています。

ここで、別の実際の例を考えてみましょう (例 B、優れた組織)。

file1.cpp

extern int x;

file2.cpp

extern int x;

file3.cpp

extern int x;
int x=3;

これもうまくいきます。3 つの .cpp ファイルはすべて x を宣言し、1 つが実際に x を定義しています。先に進んで、変数 x を操作する 3 つのファイルのいずれかの関数内にさらにコードを追加しても、エラーは発生しません。ここでも、ヘッダー ファイルを使用して、宣言が 1 つの物理ファイルにのみ入るようにする必要があります (例 B、より適切な編成)。

header.h

extern int x;

file1.cpp

#include "header.h"

file2.cpp

#include "header.h"

file3.cpp

#include "header.h"
int x=3;

最後に、うまくいかない例を考えてみましょう (例 C はうまくいきません)。

file1.cpp

int x=3;

file2.cpp

int x=3;

file3.cpp

int x=3;

各ファイルは問題なくコンパイルされます。この問題はリンク時に発生します。これは、 3 つの個別の int x 変数を定義したためです。は同じ名前で、すべてグローバルに表示されます。リンカーの仕事は、1 つのプログラムに必要なすべてのオブジェクトを 1 つの実行可能ファイルにプルすることです。グローバルに表示されるオブジェクトには一意の名前が必要です。これにより、リンカーはオブジェクトの 1 つのコピーを実行可能ファイル内の 1 つの定義済みアドレス (場所) に配置し、他のすべてのオブジェクトがそのアドレスにアクセスできるようになります。この場合、リンカはグローバル変数 x を使用してジョブを実行できないため、代わりにエラーを発生させます。

余談ですが、異なる定義に異なる初期値を指定しても問題は解決しません。各定義の前にキーワード static を付けると、変数がグローバルに表示されなくなり、定義されている .cpp ファイル内で表示されるようになるため、問題に対処できます。

グローバル変数の定義をヘッダー ファイルに入れても、本質的な変更はありません (例 C、この場合はヘッダー構成は役に立ちません)。

header.h

int x=3;  // Don't put this in a .h file, causes multiple definition link error

file1.cpp

#include "header.h"

file2.cpp

#include "header.h"

file3.cpp

#include "header.h"

ふう、誰かがこれを読んで、それから何らかの利益を得ることを願っています. 質問者は、高度なコンピューター科学者の説明ではなく、基本的な概念に関する簡単な説明を求めて叫んでいることがあります。

于 2010-05-21T05:08:15.750 に答える