3

2つのファイルがあるとします。

==ファイル1==

extern char* foo;

==ファイル2==

double foo;

これらの2つのファイルは、型の不一致にもかかわらず、g++とclang++の両方で正常にコンパイルおよびリンクされているようです。私が理解しているように、推奨される方法は、両方のファイルに含まれるヘッダーにextern宣言を配置して、File2が再定義エラーをスローするようにすることです。

私の質問は次のとおりです。

  • これにより、C ++標準に従って未定義の動作が発生しますか?そうでない場合は、File1のfooに何が入りますか?
  • リンカーはこの種の型の不一致をキャッチできますか?
4

2 に答える 2

3

これにより、C ++標準に従って未定義の動作が発生しますか?

まあ、本当の問題は、これが未定義の振る舞いなのか、それとも(標準的な用語で)不正な形式として標準によって指定されているのかということです。明らかに、それは正しくないからです。私はこれについて標準から何かを見つけようとしましたが、役に立ちませんでした。ただし、多くの同様の状況、たとえば、decl / defの不一致や、リンカーでのファンキーなもののスロー(セクション3.5、7.5を参照、または「extern」または「linkage」の検索)では、標準は通常、次のようになります。

プログラムは形式が正しくなく、診断は必要ありません。

ですから、これがここでも当てはまると仮定するのはかなり安全だと思います。これは、これが誤ったコードであり、「未定義動作」よりも最悪であることを意味します。これは、UBが特定の実装に対して何らかの合理的な動作をすることが多いためです(ただし、その動作がどうなるかを推測するべきではなく、確かにそれに依存しないでください)。投機)。「不正な形式」という用語は、標準では非常に自由に使用されており、多かれ少なかれ、コードがFUBARであることを意味していると推測できます。これはまた、リンカがこの種のエラーをキャッチできるように実装する必要がないことを意味します。そのため、リンカは正しくコンパイルおよびリンクされますが、実行するときは靴下を保持します。 。

リンカーはこの種の型の不一致をキャッチできますか?

理論的には、そうです。リンカの実装では、変数の型を(名前を操作して)外部シンボルにエンコードできるため、型が一致するもの(たとえば、オーバーロードされた関数など)へのリンクを制限したり、次の場合に診断(エラー)をスローしたりできます。タイプの不一致が発生します。前者は標準に比べて寛容すぎると思います。

ただし、私が知っているすべてのコンパイラは変数の名前を壊すわけではないため、このような不一致は「形式が正しくなく、診断は不要」であると見なすことができます。

于 2013-02-05T00:28:41.373 に答える
2

これにより、C ++標準に従って未定義の動作が発生しますか?

はい、間違いなく。

そうでない場合は、File1のfooに何が入りますか?

double foo;ええと、何にも設定されていないので、値はゼロになります。fooただし、doubleの値0は、実際にはポインターのNULLと同じであるとは言えないため、ポインターとしてdoubleと比較しようとするとどうなるかわかりませんfoo

当然、ポインタfooが割り当てられている場合、たとえばfoo = malloc(100);、doublefooにはポインタのビットが含まれますが、これは特に適切な浮動小数点数ではない可能性があります。64ビットシステムでは、上位数ビットが最も多くなるため、おそらく不正な数値です。ゼロである可能性があります。これは、値がゼロであることを意味する傾向があります。この場合、残りのビットもゼロである必要があります。ただし、浮動小数点の内部形式とポインタの実際の値によって異なります。

リンカーはこの種の型の不一致をキャッチできますか?

いいえ、C ++であっても、変数の名前は型に対して「マングル」されていません。関数のタイプが関数名にエンコードされているのは関数だけです。

技術的には、リンカまたは一部のコンパイラコンポーネントは、シンボルが表すタイプを追跡し、エラーまたは警告を出すことができます。しかし、そうするための標準からの要件はありません。あなたは正しいことをする必要があります。

于 2013-02-05T00:01:51.260 に答える