10

externの使用法を次のように説明する情報源 (書籍、オンライン資料) があります。

extern int i;        // declaration - has 'extern'
int i = 1;           // definition  - specified by the absence of 'extern'

また、次の構文をサポートするソースがあります。

extern int i;        // declaration
extern int i = 1;    // definition  - specified by the equal sign
                     // Both marked with 'extern'

私の質問は - これはCC++の区別ですか、それともANSI 以前とANSIの慣行ですか?

さて、より実際的な質問:

2 番目の構文を使用して、グローバル オブジェクト (すべてのコンパイル ユニットから参照可能) を作成します。コンストラクターはパラメーターを取らないため、括弧も等号も必要ありません。

extern MyClass myobject;

では、コンパイラはどのようにして宣言と定義を区別できるのでしょうか?

編集:学校に戻って、私は最初の構文(Borland C)に慣れていました。後で、「extern」なしで定義をコンパイルすることを拒否するコンパイラー (おそらく GCC の古いバージョン) を使用しました。それが私を混乱させた理由です。

4

6 に答える 6

12

特にあなたの例では、ここで機能しているCとC++の区別はありません。両方の言語で機能する基本的なルールは次のとおりです。宣言に初期化子が含まれている場合、それは定義です。限目。明示的であるかどうかは関係ありませexternん。初期化子がある場合、それは定義です。

つまり、名前空間スコープではとは両方ともextern int i = 1同等int i = 1です。つまりextern、そのような宣言では冗長です。C ++のオブジェクトはデフォルトで内部リンケージを持っているため、C ++では、extern宣言されたオブジェクトがの場合、定義は非冗長になります。たとえば、外部リンケージで定数を定義します。constconstextern const int c = 42;c

extern宣言に初期化子がない場合、(そしてそのときだけ)キーワードの存在に依存し始めます。externそれは非定義の宣言です。externそれがなければ定義です。(Cでは、それは暫定的な定義になりますが、それは私たちの文脈では重要ではありません)。

さて、あなたの実際的な質問のために。グローバルオブジェクトを作成するには、次のように宣言する必要があります。

extern MyClass myobject;

(これは通常ヘッダーファイルで行われます)、次にそれをいくつかの翻訳単位で次のように定義します

MyClass myobject;

コンストラクターは引数をとらないため、これがオブジェクトを定義する唯一の方法です。(C ++ 11から、必要に応じて使用することもできMyClass myobject{};ます。)

コンストラクターに引数を指定する必要がある場合(たとえば42)、両方を使用できます

MyClass myobject(42);

extern MyClass myobject(42);

定義として、初期化子の存在はそれが実際に定義として解釈されることを保証するので。

于 2012-08-08T16:46:43.480 に答える
4

ファイル スコープ変数の場合、それらがクラス型かプリミティブ型かに関係なく、次のようになります。

  • extern T t;初期化子なしは宣言です。
  • extern T t = expression;どのような構文 (代入、構築、または統合) の初期化子も定義です。
  • T t;with no initializer は定義であり、デフォルト値の に初期化されますT
  • T t = expression;定義である構文の初期化子を使用します。

extern int i = 1;と の間に違いはなくint i = 1;、両方のスタイルに対して作成する引数がありますが、ファイル スコープでの定義にはリンケージがあることを既に認識しているはずなので、一般的には 2 番目のスタイルを主張します。

歴史的に、ANSI C より前のexternキーワードは必須ではなかったようです。たとえば、http ://www.jetcafe.org/jim/c-style.html#Declarations を参照してください。

したがって、クラス型の場合extern MyClass myobject;は、宣言とMyClass myobject;定義を記述します。

于 2012-08-08T15:42:43.173 に答える
3

ドラフトn3337、3.1.2

宣言は、関数の本体(8.4)を指定せずに関数を宣言しない限り、定義です。extern指定子(7.1.1)またはリンケージ仕様25(7.5)が含まれ、初期化子も含まれません。 関数本体でもありません。クラス定義で静的データメンバーを宣言し(9.2、9.4)、クラス名宣言(9.1)であり、不透明な列挙型宣言(7.2)であり、テンプレートパラメーター(14.1)です。 )、関数定義の宣言子ではない関数宣言子のパラメーター宣言(8.3.5)であるか、typedef宣言(7.1.3)、エイリアス宣言(7.1.3)、 using-declaration(7.3.3)、static_assert-declaration(Clause 7)、attributedeclaration(Clause 7)、empty-declaration(Clause 7)、またはusing-directive(7.3.4)。[例:次の1つを除くすべてが定義です:

int a; // defines a
extern const int c = 1; // defines c
int f(int x) { return x+a; } // defines f and defines x
struct S { int a; int b; }; // defines S, S::a, and S::b
struct X { // defines X
int x; // defines non-static data member x
static int y; // declares static data member y
X(): x(0) { } // defines a constructor of X
};
int X::y = 1; // defines X::y
enum { up, down }; // defines up and down
namespace N { int d; } // defines N and N::d
namespace N1 = N; // defines N1
X anX; // defines anX
whereas these are just declarations:
extern int a; // declares a
extern const int c; // declares c
int f(int); // declares f
struct S; // declares S
typedef int Int; // declares Int
extern X anotherX; // declares anotherX
using N::d; // declares d

—例を終了]

于 2012-08-08T15:34:28.113 に答える
2

グローバルオブジェクトを作成したい (すべてのコンパイル単位から見える)

extern外部リンケージがデフォルトであるため、定義には必要ありません。

あなたがすべきことは次のとおりです:

extern MyClass myobject;

ヘッダー ファイル (これは定義ではありません) で、他のコンパイル ユニットをコンパイルするときにコンパイラがデータ型を認識できるようにします。次に、ちょうど 1 つのコンパイル単位で、次のように記述します。

MyClass myobject;

これは、外部リンケージを持つ定義です。

于 2012-08-08T15:42:53.240 に答える
2

わかりましたので、externキーワードは外部ファイルの変数名の前に置かれます。プロジェクトに別のファイルがあるとします。そのファイルが MyMath.h という名前のヘッダー ファイルであるとします (便利な関数/クラスを含む移植可能な数学ファイルを作成する場合のように)。ヘッダー ファイルには、クールな数学関数とクラスのすべてのプロトタイプ (前方参照) を配置します。この数学ヘッダー ファイルの実際のコードや関数などは、MyMath.cpp という名前の .cpp ファイルにあります (通常、すべてを整理するために同じ名前を使用します)。ここexternでキーワードが登場します。数学ファイルに PI (3.1415) のグローバル変数が必要な場合は、通常と同じように (.cpp ファイルで) それを定義する必要があります。float PI = 3.1415;次に、.h ファイルまたはヘッダー ファイルに、変数のプロトタイプまたは宣言を、プレフィックス を付けて記述しますextern

したがって、完全な例は次のようになります。

----MyMath.h----

#ifndef MYMATH_H_INCLUDED
#define MYMATH_H_INCLUDED

extern float PI;

#endif // MYMATH_H_INCLUDED

----MyMath.cpp----

#include "MyMath.h"

float PI = 3.1415;

----main.cpp----

#include <iostream>
#include "MyMath.h"

using namespace std;

int main()
{
    cout << "PI = " << PI << endl;
    return 0;
}

私は徹底的に説明したいと思います!これは、ファイル間で変数を使用するためのものであることを忘れないでください。

于 2014-06-15T21:21:42.570 に答える
0

「initializer」は「extern」に勝ります。行動は話に勝る。

于 2013-08-07T19:34:43.127 に答える