11

ヘッダーに文字配列が定義されています

//header.h
const char* temp[] = {"JeffSter"};

#define されている場合、ヘッダーは保護され、先頭に #pragma once があります。このヘッダーが複数の場所に含まれている場合、LNK4006 - char const * * temp already defined in blahblah.obj を取得します。それで、これについていくつか質問があります

  1. 警備員を配置しているのに、なぜこれが起こるのですか? 最初のアクセス後にヘッダーが読み取られないようにしていると思いました。
  2. このヘッダーの多数の列挙型が LNK4006 警告を出さないのはなぜですか?
  3. 署名の前に static を追加すると、警告は表示されません。このようにすることの意味は何ですか。
  4. エラーを回避するためのより良い方法はありますが、ヘッダーで配列を宣言できます。配列定義のためだけに cpp ファイルを用意するのは本当に嫌です。
4

5 に答える 5

14

警備員を配置しているのに、なぜこれが起こるのですか? 最初のアクセス後にヘッダーが読み取られないようにしていると思いました。

インクルード ガードは、ヘッダーが1 つのファイル(翻訳単位) に 1 回だけ含まれるようにします。ヘッダーを含む複数のファイルの場合、各ファイルにヘッダーを含める必要があります。

ヘッダー ファイルで外部リンケージ (グローバル変数) を使用して変数を宣言するのとは対照的に、 を定義することにより、ヘッダーを一度のソース ファイルにのみ含めることができます。複数のソース ファイルにヘッダーを含めると、変数の複数の定義が存在することになりますが、これは C++ では許可されていません。

したがって、お気づきのように、まさに上記の理由から、ヘッダー ファイルで変数を定義するのは悪い考えです。

このヘッダーの多数の列挙型が LNK4006 警告を出さないのはなぜですか?

それらは「グローバル変数」を定義しないため、型などに関する宣言にすぎません。ストレージを予約しません。

署名の前に static を追加すると、警告は表示されません。このようにすることの意味は何ですか。

変数を作成すると、静的スコープstaticが設定されます。オブジェクトは、それが定義されている翻訳単位 (ファイル) の外では見えません。したがって、簡単に言えば、次の場合:

static int i;

ヘッダーでは、ヘッダーをインクルードする各ソース ファイルは個別 intの変数を取得しますiが、これはソース ファイルの外では見えません。これは内部リンケージとして知られています。

エラーを回避するためのより良い方法はありますが、ヘッダーで配列を宣言できます。配列定義のためだけに cpp ファイルを用意するのは本当に嫌です。

配列をすべての C++ ファイルから見える 1 つのオブジェクトにしたい場合は、次のようにする必要があります。

extern int array[SIZE];

をヘッダー ファイルに追加し、変数を必要とするすべての C++ ソース ファイルにヘッダー ファイルをインクルードしますarray。ソース ( ) ファイルの1 つで、以下.cppを定義する必要がありますarray

int array[SIZE];

ヘッダーとソース ファイルの違いによる間違いを見つけられるように、上記のソース ファイルにもヘッダーを含める必要があります。

基本的に、 「はどこかで定義されており、型とサイズを持ってexternいる」ことをコンパイラに伝えます。次に、実際に定義するのは 1 回だけです。リンク段階では、すべてがうまく解決されます。arrayintSIZE array

于 2010-01-20T23:17:07.530 に答える
5
  1. ヘッダー ガードは、プログラム全体で複数の定義を防止することとはまったく関係ありません。ヘッダー ガードの目的は、同じヘッダー ファイルが同じ翻訳単位(.cpp ファイル) に複数含まれないようにすることです。つまり、同じソース ファイル内に複数の定義が存在するのを防ぐために存在します。そして、それらはあなたの場合に意図したとおりに機能します。

  2. C++ での複数定義の問題を管理する規則は、1 つの定義規則 (ODR) と呼ばれます。ODR は、エンティティの種類によって定義が異なります。たとえば、はプログラム内で複数の同一の定義を持つことができます。それらは、それらが使用されるすべての翻訳単位で定義できます (そしてほとんどの場合そうしなければなりません)。これが、列挙型定義がエラーにならない理由です。

    外部リンケージを持つオブジェクトは、まったく別の話です。それらは、1 つの翻訳単位でのみ定義する必要があります。tempこれが、ヘッダー ファイルを複数の翻訳単位にインクルードすると、 の定義によってエラーが発生する理由です。インクルード ガードでは、このエラーを防ぐことはできません。ヘッダー ファイルで外部リンケージを持つオブジェクトを定義しないでください。

  3. 追加することで、オブジェクトに内部リンケージstaticを与えます。ODR の観点からは完全に問題ないため、これでエラーが消えます。ただし、これにより、ヘッダー ファイルが含まれる各翻訳単位に独立したオブジェクトが定義されます。同じ効果を得るには、次のこともできますtemp

    const char* const temp[] = { "JeffSter" }; 
    

    constC++ のオブジェクトにはデフォルトで内部リンケージがあるためです。

  4. これは、外部リンケージを持つオブジェクト (つまり、プログラム全体に 1 つ) が必要か、内部リンケージ (各翻訳単位に固有) を持つオブジェクトが必要かによって異なります。後者が必要な場合は、上記のようstaticに and/or extraを使用constしてください (それがうまくいく場合)。

    前者 (外部リンケージ) が必要な場合は、非定義宣言をヘッダー ファイルに入れる必要があります。

    extern const char* temp[];
    

    定義を 1 つだけの .cpp ファイルに移動します。

    char* const temp[] = { "JeffSter" }; 
    

    ヘッダー ファイルでの上記の宣言は、ほとんどの目的で機能します。ただし、temp未知のサイズの配列 (不完全な型) として宣言しています。既知のサイズの配列として宣言する場合は、サイズを手動で指定する必要があります

    extern const char* temp[1];
    

    宣言と定義の間で同期を保つことを忘れないでください。

于 2010-01-20T23:16:35.270 に答える
4

インクルード ガードは、同じヘッダーを同じファイルに繰り返しインクルードしないように保護しますが、別のファイルにインクルードすることはできません。
何が起こるかというと、リンカはtemp複数のオブジェクト ファイルを認識しtempます。静的にするか、名前のない名前空間に配置することで解決できます。

static const char* temp1[] = {"JeffSter"};
// or
namespace {
    const char* temp2[] = {"JeffSter"};
}

tempまたは、ヘッダーで extern として定義して宣言する 1 つのソース ファイルを使用することもできます。

// temp.cpp:
const char* temp[] = {"JeffSter"};

// header.h:
extern const char* temp[];
于 2010-01-20T23:08:04.010 に答える
0

「決して」は広すぎると思うので、ヘッダーで変数を定義しないというアドバイスには敬意を表して同意しません。それにもかかわらず、私をこのスレッドに連れてきたエピソードは、あえてそうすることを敢えてする人々への警告の物語を提供します.

警告 LNK4006 の原因を調査した結果、このページにたどり着きました。これは、DLLMain ルーチンを定義する翻訳単位から、ほとんどの翻訳単位に含まれるプライベート ヘッダーに移動したばかりの確立された配列を呼び出します。このライブラリを構成するもの。私は過去 11 年間にこのライブラリを何百回もコンパイルしてきましたが、これまでこの警告を見たことがありませんでした。

このページを読んだ直後に、エラーの原因を発見しました。これは、定義が、DLLMain も定義するモジュールで定義されている他のすべてを保護するガード ブロックの外にあることでした。これは、通常、すべてのメモリ ブロックを収集する場所です。外部連携が必要です。予想どおり、テーブルをガード ブロック内に移動すると、警告がなくなり、新しい外部リンク テーブルに関連する 2 つの問題だけが残りました。

要点:ヘッダーで変数を定義でき、共通ブロックを配置するのに最適な場所ですが、注意してください。

于 2016-07-16T09:05:54.167 に答える
-2

お待ちください...宣言を混同しています...「char const * * temp」と言いましたが、ヘッダー ファイルには「const char* temp[] = {"JeffSter"};」があります。

C FAQのセクション 6.1 の「セクション 6. 配列とポインター」を参照してください。

6.1: 1 つのソース ファイルに char a[6] という定義があり、
    別の extern char *a を宣言しました。なぜうまくいかなかったのですか?

A: 1 つのソース ファイルで文字の配列を定義し、
    other 文字へのポインタを宣言しました。宣言
    extern char *a は実際の定義と一致しません。
    type pointer-to-type-T は array-of-type-T と同じではありません。
    extern char a[] を使用します。

    参考文献:ISO Sec. 6.5.4.2; CT&P課 3.3 pp. 33-4、秒。4.5
    pp.64-5。

それが問題の原因です。宣言と定義を一致させます。これが鈍く聞こえる場合は申し訳ありませんが、リンカーがあなたに言っていることに気付かずにはいられませんでした...

于 2010-01-20T23:12:13.160 に答える