0
#include <stdio.h>

namespace myname{
    double var = 42;
}

extern "C" double _ZN6myname3varE = 10.0;

int main(){
    printf("%d\n", _ZN6myname3varE);
    return 0;
}

gccコンパイル結果は次のとおりです。

Jim@ubuntu:~/workspace/vi_edit$ g++ testSymble.cpp -o testSymble
testSymble.cpp:7:19: warning: ‘_ZN6myname3varE’ initialized and declared ‘extern’ [enabled by default]
testSymble.cpp: In function ‘int main()’:
testSymble.cpp:10:32: warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘double’ [-Wformat]
/tmp/cczIjRfH.s: Assembler messages:
/tmp/cczIjRfH.s:14: Error: symbol `_ZN6myname3varE' is already defined

なぜ_ZN6myname3varE再定義されるのですか?
警告の‘_ZN6myname3varE’ initialized and declared ‘extern’ [enabled by default]意味は何ですか?


この句で明示的に許可されている場合を除き、名前が予約されているコンテキストでプログラムが名前を宣言または定義する場合、動作は未定義です。

17.4.3.1.2 グローバル名
2 つのアンダースコア (_ _) を含む名前、またはアンダースコアの後に大文字が続く名前 (2.11) は、実装用に予約されています。

4

2 に答える 2

3

なぜ_ZN6myname3varE再定義されるのですか?

C++ 変数myname::varは、GCC によって名前マングルされます。_ZN6myname3varEと呼ばれる C (つまりマングルされていない) 変数も定義しました_ZN6myname3varE。したがって、同じシンボルの複数の定義があります。


警告[...]とはどういう意味ですか?

標準的な使用法は次のとおりです。

foo.h

extern "C" int myvariable;

foo.c/cc

#include "foo.h"

int myvariable = 42;

C++ 標準で変数の初期化が許可されているかどうかはわかりませんextern "C"(つまり、あなたが行っているように)。しかし、コンパイラは確かに、あなたがしていることはおそらく意味をなさないことを警告しています。

于 2013-07-17T04:42:55.423 に答える
0

最初の警告メッセージはextern、変数の宣言に含める場合、初期化子も含めることができないことを意味します。したがって、これらの行は両方ともその警告を生成します。

extern "C" int i = 9;
extern     int j = 10;

次のいずれかを書くことができます:

int i = 9;
int j = 10;

また:

extern "C" int i;
extern     int j;

または ( Adam Rosenfieldがコメントで指摘しているように)、イニシャライザを許可するために行に中括弧を含めることができます。

extern "C" { int i = 9; }

= 42コードに適用すると、初期化子を行に入れることができないextern "C"か、次のように記述する必要があります。

extern "C" { double _ZN6myname3varE = 10.0; }

孤立して、最終的な問題を無視すると、それは「機能する」はずです。

2 番目の警告は、それnamespace myname { double var = 42; }が a であるdoubleため、%d変換指定が間違っていることを意味します。%fこのテーマのまたは%eまたは%gまたはバリアントである必要があります。

printf("%f\n", myname::var);

3 番目のメッセージであるエラーは、アセンブラーからのものです。最初のメッセージは単なる警告だったので、実際には 2 つの異なる定義があり、マングルすると_ZN6myname3varE、2 つの異なる初期化子を使用して に変換されます。許可される定義は 1 つだけです — 1 つの定義ルールです。

ただし、アンダースコアで始まり大文字が続く名前は実装用に予約されているため、名前_ZN6myname3varEを直接使用しようとすると、未定義の動作が発生します。未定義の動作をいじらないでください。それを避けてください。

于 2013-07-17T05:11:34.643 に答える