• 締切済み

C++プログラムをCで呼び出したい

こんにちは。質問させていただきます。 現在、Linux/GCC3.2.3系でC言語の開発をしています。 私自身のレベルとしては、C言語での実務は1年未満。C++はゼロ。本業はJavaプログラマを数年やっております。 さっそく本題です。 既にC++で作成されたある一連のプログラム群(20本程度)があり、これらC++の関数をC言語で作成されたプログラムから呼び出して使用したいと思っています。 C++プログラムは既にテスト済みなので、これらのソースは基本的には手を加えず、そのままライブラリ化などして使用したいと考えています。 そこで質問なのですが、C言語から呼び出せるような形式でC++ソースをライブラリ化する方法と、C言語からの呼び出し方を教えていただけないでしょうか?

みんなの回答

回答No.7

Cで書かれたプログラムをC++から呼び出すことは、何とかなりますが、その逆は相当困難を 伴います。 C++は、関数の多重定義があるため、プログラムからC++を呼び出すと、リンクエラーが起きます。 これを避けるためには、呼ばれる側のC++のプログラムを書き換えなければなりません。 >既にC++で作成されたある一連のプログラム群(20本程度 から、多重定義の無くし、関数宣言に  extern "C" 書き換えなければなりません。 これは大変手間がかかるでしょう。 cには、classがないため、クラスを引数にするC++の関数が呼び出せません。 参照型もだめでしょう。 結局、(拡張子は.cのままでも) g++でコンパイルしなければなりません。 逆にC++から、cプログラムを呼ぶためには、 extern "C" funtion1(... extern "C" funtion2(... の様に、呼び出す関数の宣言をしたヘッダファイルを作っておけば済みます。 (既存のプログラムに修正を加える必要はないでしょう) nepiatissueさんは、Javaのプログラムの経験があるということなので、 C++はすぐマスター出来るでしょう。 このほうが、この方が工数は少なくなるでしょう。 Cにオブジェクト指向の考えを足した物がC++ C++から、Cの欠点を取り除いて設計されたものがJava そう考えれば気が楽になるのではないでしょうか?

  • jacta
  • ベストアンサー率26% (845/3158)
回答No.6

全体をC++として扱う方法に関して、一言コメントしておきます。 C++を使う上で、オブジェクト指向やジェネリックプログラミングは使わなくても問題ありませんし、知らなくてもやはり問題ではありません。しかし、例外処理について正しく理解していないと、とんでもないことになります。 C++を使っているのに、C言語と同等の認識しかないと、どこから例外が飛び出してくるかわからないために、実行パスが非常に複雑であることに気が回りません。 結果として、メモリをはじめとしたリソースのリークや、データが半壊して整合性が保てなくなるような事態が頻発します。 開発スタッフが、C++の経験は浅くても、Javaの経験がそれなりにあるのであれば、両方の合わせ技である程度はどうにかなると思いますが、C++とJavaでは例外安全を実現する方法が若干違うので、その辺りはあらかじめ十分検討しておくべきです。

  • a-saitoh
  • ベストアンサー率30% (524/1722)
回答No.5

要件としてCが指定されているのに,C++を内部で呼び出して使って許されるのですか? ふと気になりました.

  • MrBan
  • ベストアンサー率53% (331/615)
回答No.4

#1です。 ラッパーを含むような両用のヘッダは、_cplusplus マクロで ifdef するのが定石です。 extern "C" 自体は C++ の構文なのでこの部分を上記マクロで囲んで区別、それ以外は C でも C++ でも共通して有効なコードのみで実装します。 ある案件で同様なラッパーライブラリを書いたことがありますが、そのときは jacta さんの書かれている「不完全なポインタ」でハンドリングしました。 Cのコードはこれから書くのであれば C++ を意識したCのコードになるでしょうから面倒は最小限だと思いますが、一般的には C -> C++ より C++ -> C の方が楽なのは確かかと。 全てC++でかけるならそれが最高だと思うので、交渉がんばってください。 保守要員などを理由に渋られる場合、いわゆる「better C」(クラスなどを使わない、C++によるCのような書き方(構造化ベース)」とを提案してみるのも効果があるかもしれません。

  • jacta
  • ベストアンサー率26% (845/3158)
回答No.3

基本的には、extern "C"によってC結合を指定した関数を間に挟むことになります。 他に注意すべき点としては、C++にはあるが、Cにはない型があるので、それらを適切にマッピングする必要があります。例えば、 bool → _Boolまたはint 参照型 → ポインタ型 クラス → 不完全型のポインタを用いるなどの方法でハンドル化する(クライアントコードから内部を隠蔽する) という具合です。 また、多分大丈夫だとは思いますが、列挙型を使用している場合には、若干の不安が残ります。int型に置き換えるなどした方がよいでしょう。 もう一点、C++の例外が外部に送出されても、Cプログラムではどうすることもできませんので、ラッパ関数内部でcatchした上で、エラーコードを返すなどの方法に置き換える必要があります。

nepiatissue
質問者

お礼

回答ありがとうございます。 まだ全部の関数をチェックした訳ではないのですが、こちらが必要としている箇所では、今のところC言語で使用できない型などはなさそうなので安心です。 例外処理もC言語ではキャッチできないですよね。こちらも考慮したいと思います。

  • galluda
  • ベストアンサー率35% (440/1242)
回答No.2

がると申します。 んっと…C言語のルーチンをC++で、という方向性はともかく、逆は、ちと危険な部分が多々伴うかと考えられます。 物凄く「あれ」な発言にはなりますが。C言語のソースをそのまま「C++として」解釈、コンパイルも可能なので(std名前空間の取り込みなど、微妙に異なる部分もありますが、全体としてさほど大きな変更量ではないと思うので)。 もしそのあたりで問題がなければ、あくまでも全体を「C++として」取り扱ったほうが、様々な問題が発生しにくいと思われるのですがどんなもんでしょうか?

nepiatissue
質問者

お礼

回答ありがとうございます。 全体的にC++としてコンパイルした方が無難なんですね。一応、要件として「C」が指定されてますので、Cとしてコンパイルしてみますが、C++としても可能かどうか相談はしてみます。

  • MrBan
  • ベストアンサー率53% (331/615)
回答No.1

C から呼ぶことができる C++ の関数は、基本的に以下の宣言があるものだけです。 extern "C" これがないと同盟の別物としてリンクに失敗します。 一般的には、間にラッパーとなる上記を指定した関数をはさむのが常道かと思います。 COM を C から呼び出すラッパーがDirectX 等にありますので、参考になるかと思います。 C++ のソースが、どのようなものかにもよりますが、グローバルな関数であれば、そのソースを #include して、extern "C" { } で囲むこともできるかと思います。 PODでないクラスのオブジェクトなどを直接渡すのは危険です。 確保したメモリの受け渡しなども注意が必要で、 自動変数を含むオブジェクトの受け渡しなども危険です。 例外などもCの方には伝播させることができません。

nepiatissue
質問者

お礼

回答ありがとうございます。 extern宣言を追加すればOKなのですね。 ところで、まだDirectXのソースは見てないのですが(見てから質問しろ、と言われそうですが・・・^^;)、ラッパー関数自体はC++で作成するのでしょうか?C言語で作成するのでしょうか?