2017-10-23 16 views
-1

正しく覚えていれば。このコードはうまくいくはずです。C++はCの構造体ポインタパラメータを持つC関数を呼び出す

#ifdef __cplusplus 
extern "C" { 
#endif 

    typedef struct { 
     int a; 
    } Base; 

    typedef struct { 
     int a; 
    } Derived; 

    void Init(Base* b) { 
     b->a = 1; 
    } 
#ifdef __cplusplus 
} 
#endif 


int main() { 
    Derived d; 
    Init(&d); // error can not convert argument 1 from 'Derived *' to 'Base *' 
} 

これはCソース(extern "C"なし)としてコンパイルされます。どのように私はそれをCの部分を変更せずにC + +としてコンパイルすることができますか?

編集:CとC++の両方で実際にコピーしてテストできるようにコードを修正しました。

+8

をあなたが実際に 'Base'から' Derived'を得ていない:C導出で

は通常埋め込むことによってシミュレートされます。 –

+0

@RichardHodgesその部分はCソースです。 C++ではありません。 –

+2

@ J.Doeそうでない場合、コンパイラは 'Derived *'を 'Base *'にどのように変換するべきですか? – Darhuuk

答えて

4

C言語でタイプ濫用がより受け入れられるため、Cでコンパイルされます(警告が生成されます)。コンパイラが標準の違反を許すのは一般的です。

あなたが reinterpret_castへのポインタが必要です++ Cで

Init(reinterpret_cast<Base*>(&d)); 

または

Init((Base*)&d); 

を理想的には、関数やクラスあなたの最小の保守性・スイートには、このポインタの乱用をカプセル化したいと思いますできる。

+1

関連するコードはCとC++の両方でエラーです。この "タイプの乱用"はどちらの言語でも許されません。エラーを報告するために使用される言葉は、コンパイラを書く人の選択によるものです。 –

+0

@ M.M gccによるものではありません。https://godbolt.org/g/v63oS1 –

+1

あなたはそのリンクが説明しようとしているとはっきりしていません。 gccの作者は、このエラーを報告するときに "warning"という単語を使用することにしました。 –

2

Derivedの名前はミッドリーディングです。あなたはからDerivedを派生しておらず、Cの構造的同値性はあまり意味がありません。これはキャストで動作する可能性がありますが、コンパイラの助けを借りずにこの同値を保つ必要があります。いつの日かあなたがBase定義に

typedef struct { 
    int a; 
    int c; /* New field */ 
} Base; 

を変更することを決定したとき、あなたはすべての「派生」定義を変更する必要があります。

#ifdef __cplusplus 
extern "C" { 
#endif 

    typedef struct { 
     int a; 
    } Base; 

    typedef struct { 
     Base base; 
    } Derived; 

    void Init(Base* b) { 
     b->a = 1; 
    } 
#ifdef __cplusplus 
} 
#endif 

int main() { 
    Derived d; 
    Init(&d.base); 
} 
関連する問題