C ++コンパイラーはどのようにして外部変数を見つけますか?


15

このプログラムをg ++とclang ++でコンパイルします。違いがあります:
g ++は1を出力しますが、clang ++は2を出力
します
。g++:extern変数は最も短いスコープで定義されているようです。
clang ++:extern変数は最短のグローバルスコープで定義されます。

C ++仕様にはその仕様がありますか?

main.cpp

#include <iostream>
static int i;
static int *p = &i;

int main() {
  int i;
  {
    extern int i;
    i = 1;
    *p = 2;
    std::cout << i << std::endl;
  }
}

other.cpp

int i;

バージョン:g ++:7.4.0 / clang ++:10.0.0
コンパイル:$(CXX)main.cpp other.cpp -o extern.exe


4
コンパイラーは、外部参照を持つ変数としてそれらをマークする以外はexternで何も行いません。リンカーは、コンパイルされたすべてのオブジェクトファイル間のリンクを解決しようとします。
SPlatten

すばらしい(奇妙な)質問です!MSVCclang-cl(両方ともgive 2)でコードをいじってみると、両方extern int iで完全に無視されているようother.cppです。ファイルにリンクしなくても、プログラムがビルドされて実行されます。
Adrian Mole

1
@SPlattenおそらく、リンカはへの参照を「解決」する必要がないためi、試行しません。
エイドリアンモル

3
関連する古い一時停止されたGCCバグはここにあり、対応するオープンClangバグはここにあります
ウォールナット

回答:


11

[basic.link/7]は規格の関連部分である必要があります。現在のドラフトでは、それは言う:

ブロックスコープで宣言された関数の名前とブロックスコープextern宣言で宣言された変数の名前はリンクしています。そのような宣言が名前付きモジュールに添付されている場合、プログラムは不正な形式です。2つの宣言が同じ宣言領域にある場合、ブロックスコープ宣言が(形式が正しくない可能性があります)再宣言になるように、リンケージがあるエンティティの目に見える宣言があり、最も内側の名前空間スコープの外側で宣言されたエンティティを無視します。ブロックスコープ宣言は、同じエンティティを宣言し、前の宣言のリンケージを受け取ります。そのような一致するエンティティが複数ある場合、プログラムの形式は正しくありません。それ以外の場合、一致するエンティティが見つからない場合、ブロックスコープエンティティは外部リンクを受け取ります。翻訳単位内で、同じエンティティが内部リンクと外部リンクの両方で宣言されている場合、プログラムの形式が正しくありません。

次の例はあなたのケースとほぼ正確に一致することに注意してください:

static void f();
extern "C" void h();
static int i = 0;               // #1
void g() {
  extern void f();              // internal linkage
  extern void h();              // C language linkage
  int i;                        // #2: i has no linkage
  {
    extern void f();            // internal linkage
    extern int i;               // #3: external linkage, ill-formed
  }
}

したがって、プログラムの形式は正しくありません。説明は例の下にあります:

行#2の宣言がない場合、行#3の宣言は行#1の宣言とリンクします。ただし、内部リンケージ付きの宣言は非表示であるため、#3には外部リンケージが与えられ、プログラムの形式が不適切になります。


この例のプログラムは、外部リンケージがどこにも定義されていないため、形式が正しくありません。これは、OPの例には当てはまりません。
n。「代名詞」m。

3
@n。 '代名詞' m。ただし、この規則は翻訳単位に適用されます。翻訳単位内で、同じエンティティが内部リンクと外部リンクの両方で宣言されている場合、プログラムの形式は正しくありません。
Daniel Langr

2
答えはC ++ 17以降にのみ適用されます。CWG問題426の解決を参照してください。その変更前は、GCCが正しかったように思えます。
クルミ

さて、私は標準の前の版を読んでいたようです。
n。「代名詞」m。
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.