2017-05-05 13 views
3

CとC++の両方を使用するプロジェクトでは、.hファイルには型の定義が含まれています。その定義がヘッダーがcまたはcppファイルに含まれているかどうかによって異なりますが、1つの定義ルールに違反していますか?プリプロセッサ分岐を実装した構造体はODR違反ですか?

// my_header.h 
struct MyStruct 
{ 
#ifdef __cplusplus 
    std::size_t member; 
    int surprise; 
#else 
    unsigned member; 
#endif 
}; 

私はODRは異なる翻訳単位に関係していることを知っているが、中に「私の場合は、」異なる翻訳単位は、一般的な構造体の異なる実装を持つまで終了しませんか?私はこれを生産コードで見てきましたが、最初はこの場合リンカが何をしているのか不思議でした。

どのような考えですか?

+0

CPPコンパイラで '驚き 'しか使用しないことを覚えている限り、あなたはうまくいくはずです。これらの条件文のうちの1つだけがコンパイルされるので、コンパイラはそれを見ません。 –

+0

@GillBates私が取り組んでいるプロジェクトには、CとC++の両方のソースファイルがあります(両方のコンパイラが使用されています)。ああ、あなたは2つのリンカーもあるので、probもないということですか? –

+0

C++は実際には、プログラムの一部が別の言語で書かれているときに何が起こるかを指定していますか?それともこれは未定義ですか? – Leushenko

答えて

4

コンパイラ(CまたはC++)を1つ使用する限り、問題は発生しません。ヘッダーファイルにはどのような拡張子があるかは関係ありません。

異なる言語の翻訳単位をリンクしている場合は、はい、ODRに違反しています。

これは全体的にエラーが発生しやすいようです。私はC++型にまったく別の名前を付けるだろう。マクロを使用して2つの間で切り替えることができます。typedef周辺のプリプロセッサを使用していますか?

+0

今私は上司に不平を言うことができず、10年以上前のコードを削除するよう求めています。(はい、2つのコンパイラが使用されています:() –

+3

@LorahAttkins: ODRの違反があると思われる場合は、問題追跡システムを使用してください。そうでない場合でも、これは本当に悪い設計であり、バグ番号に値する価値があります。大きなバージョン。 –

+1

C言語用のODRとC++のODRがありますが、それは違反しません。CとC++の混在プロジェクト用のODRはありません。標準によってカバーされていない。 –

2

はい、私は考えています(おい、ごめんなさい、あなたに尋ねました)。コードをそのように書かないでください。さて、これを最後まで正しい方法で予約します。しかし、限りあなたの質問に行く:はい、これは、ODRの違反になりますあなたのビルドプロセスの一環としてCとC + +の両方のコンパイラを使用する場合。実際のファイル拡張子は無関係かもしれません(コンパイラのデフォルトを変更するかもしれませんが、ビルドシステムはコンパイラの言語を明示的に指定するかもしれません)。つまり、CはC++の適切なサブセットであるため、C++コンパイラで構築できるCコードを書くのがはるかに一般的になるため、これは非常に悪い考えであり、非常に珍しいことです。また、CとC++の両方のコンポーネントを持つプロジェクトでは、C++コンパイラを使用し、純粋なCのプロジェクトでもそのコードを使用できます。したがって、ファイルの拡張子に関係なく、指定されたプロジェクトが1つのコンパイラのみに依存する限り、これは問題ありません。

// my_header.h 
#ifdef __cplusplus 
    constexpr bool is_cpp = true; 
#else 
    constexpr bool is_cpp = false; 
#endif 

struct cpp { 
    std::size_t member; 
    int surprise; 
}; 

struct cc { 
    unsigned member; 
}; 

template <bool CPP> 
struct MyStructImpl : private std::conditional_t<cpp, cc, CPP> 
{ 
}; 

using MyStruct = MyStructImpl<is_cpp>; 

これは、同じように定義し、無条件にかかわらず、マクロのオプションのされている構造体で、できるだけ多くのコードを保持し、かつできるだけ遅くにマクロ関連するものを延期します。これはまた、ツーリングとテストの点でも大きな勝利です。再コンパイルせずに両方のバージョンの構造体に対して単体テストを実行することができます。

+0

私はすでに生産コードでこのことを__seen__しています。私はそれを書いたとは決して言わなかった。私はすでに私に悪い見えるものすべてを出している:ODR、リンカー。私は原告として尋ねています –

+0

シンプルな 'struct MyStruct {size_t member、int surprise};' *とC++両方のためになぜでしょうか? –

+0

@LorahAttkinsはい申し訳ありませんが、確かに私は告発するつもりはありませんでした。あなたは、マクロを持つそのような条件付き構造体がC/C++全体のものとは独立した悪い考えであることを、あなたの同僚などに伝えることができます。 –

3

2例があります

  • (所与のプログラムのための)ヘッダを含むすべての翻訳単位が同じ言語(CまたはC++)としてコンパイルされている:

    ==>なし問題。

  • ヘッダーを含む一部の翻訳単位はCとして翻訳され、一部はC++として翻訳されます。

    ==> ODR違反。

しかし、ODR違反が唯一の「未定義の動作」であり、実際、すべてのその多くはありません、それは「いくつかの漠然とした提案を除いて(一緒++ CとCをべきで連携についての規格でを定義されている働く ")。言い換えると、CとC++を一緒にリンクしている場合は、おそらく実装の詳細に依存していると思われます。

一般に、std::size_tunsignedが同じサイズになるように32ビットをコンパイルしていて、C++がすべての割り当てを行い、Cでこれらのものの配列を扱わないなら、おそらくそれで逃げるでしょう。

1

ODRを違反することは、複数の言語を一緒にリンクしているときには何を意味するのかはわかりません。 C++標準は、Cオブジェクトファイルで定義できるものについては、何も言及していません。struct私たちはこのようにして「アセンブリ言語」(一般的な実装に基づいて)に答えなければなりません。答えは(すでに雄弁に与えられているように)ワットです。