C++関数からCの関数を呼ぶには extern "C" を使うのはわかるのですが
C関数からC++の関数を呼ぶ方法がわかりません。
『外部参照 1 が未解決』になってリンクが出来ません。

ちなみにC++の関数はDLLで、他のC++関数からは呼ぶことも実行出来ることも
確認済みです。

よろしくお願いします。

このQ&Aに関連する最新のQ&A

A 回答 (1件)

基本的に、呼ぶことができません。

と言うのも、c++ には、関数のオーバーロードと
言う機能があって、同じ関数名でも、引数の並び(型や個数)が違うと別の関数として
扱われます。

この機能は c にはありませんから、たとえひとつしかその名前の関数を書いてなくても
オーバーロードの仕組みを持った関数になるわけですから、それは c から呼ぶことは
できません。


> C++関数からCの関数を呼ぶには extern "C" を使うのはわかる

正確には、そうじゃないんです。

c++ は、型のチェックが厳密ですから、関数を呼ぶ場合には、そのプロトタイプ宣言が
必須です。

普通に書くと、c の関数なのか、c++ の関数なのかの区別が付かないので、c の
関数なんだよ、と宣言をするのが extern "C" なんです。

で、本題に戻って、「c++ で記述した関数を c から呼ぶには?」ということなの
ですが、答えは「extern "C" で宣言をした、c++ の関数を作る」ということに
なります。

例えば、以下の関数は思いっきり c++ で記述した関数ですから、関数自体は c++
じゃないとコンパイルできませんが、c から呼ぶことが可能です。

★ヘッダ

#ifdef __cplusplus
extern "C" {
#endif

void print_string(char*);

#ifdef __cplusplus
}
#endif


★ソース

#include "ヘッダファイル"
#include <iostream.h>

void print_string(char* str)
{
cout << str << endl;
}
    • good
    • 0
この回答へのお礼

早速の回答ありがとうございました。
例示もあってとても助かりました。
これを参考にプログラムを修正します。
突然プロトタイプの担当者に指名されて
パニック状態なので本当に助かりました。
ありがとうございます。

お礼日時:2001/10/17 09:00

このQ&Aに関連する人気のQ&A

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!

このQ&Aを見た人はこんなQ&Aも見ています

このQ&Aを見た人が検索しているワード

このQ&Aと関連する良く見られている質問

QC++の関数をCで呼ぶには??

C++の関数をCで呼ぶには、「extern C」を使用することが有名だと思いますが、これだとC++で記述したソースコードにextern Cを追加することにあると思います。
では、C++のほうはまったく手をつけず、C++の関数をCで呼ぶことは可能なのでしょうか?
知っている方がいましたらよろしくお願い致します。

Aベストアンサー

一般的には不可能です。既存のC++コードを修正することなく、Cから呼び出すには、

extern "C++" void f();

extern "C" int call_f() throw()
{
 try
 {
  f();
 }
 catch (...)
 {
  return -1;
 }
 return 0;
}

のようなラッパー関数を作り、それを呼び出す必要があります。

なお、C++の関数のマングル名を調べて強引に呼び出すことも、場合によっては可能ですが、処理系によってはC++結合とC結合のコーリングコンベンションが異なる場合があるので要注意です。また、仮に問題なく呼び出せたとしても、C++の関数から送出された例外を処理することができませんので、破綻するのは目に見えています。

Qc++,ある関数のクラスから別のクラスの関数を呼ぶ

c++で、あるクラスのメンバ関数から、別のクラスのメンバ関すを呼びたいのですが、どのようにしたらできますか?
例えば、以下のような単純なコードを考えています。やりたいことは、Aのメンバ関数であるaaa()からBのクラスであるbbb()を呼びたいと思っています。その理由を少し説明します。ここでは、Aというクラスとmain関数はオープンソースコードを例えています。できるだけ、元のオープンソースコードを書き換えずに新たな機能を拡張したいと思っています。そこで、Bというクラスを使って、元のオープンソースコードに機能を拡張しようとしています。このような理由なので、bbb()という関数はaaa()という関数から呼びたいです。メイン関数には何も書き加えないのがベストです。
現状では、実行すると「this is aaa」という出力しか出ません。ここに「this is bbb」の出力を加えたいです。クラスAとBにある程度コマンドを追加して、解決できないでしょうか。

#include <iostream>
using namespace std;

//------------------------------------------------------
class A{
public:
void aaa();
virtual void bbb(){}
};
//------------------------------------------------------

//------------------------------------------------------
class B : public A{
public:
void bbb();
};
//------------------------------------------------------

//------------------------------------------------------
void A::aaa()
{
cout << "this is aaa \n";
bbb();
}
//------------------------------------------------------

//------------------------------------------------------
void B::bbb()
{
cout << "this is bbb \n";
}
//------------------------------------------------------

//------------------------------------------------------
int main()
{
A a;
a.aaa();
return 0;
}
//------------------------------------------------------

c++で、あるクラスのメンバ関数から、別のクラスのメンバ関すを呼びたいのですが、どのようにしたらできますか?
例えば、以下のような単純なコードを考えています。やりたいことは、Aのメンバ関数であるaaa()からBのクラスであるbbb()を呼びたいと思っています。その理由を少し説明します。ここでは、Aというクラスとmain関数はオープンソースコードを例えています。できるだけ、元のオープンソースコードを書き換えずに新たな機能を拡張したいと思っています。そこで、Bというクラスを使って、元のオープンソー...続きを読む

Aベストアンサー

Aを極力触りたくないのであれば、あまりカッコよくありませんが、AがBを継承するではどうでしょうか?
提示コードを以下のように書き換えれば、とりあえず期待する動きはすると思います。

//------------------------------------------------------
class B {
public:
virtualvoid bbb();
};
//------------------------------------------------------

//------------------------------------------------------
class A: public B{
public:
void aaa();
};
//------------------------------------------------------
※ その他はそのまま

QC++のクラスで継承先の仮想関数をコンストラクタで呼ぶ方法について

タイトルのとおり、C++のクラスで自分のクラスを継承した先の仮想関数をコンストラクタで呼ぶ方法についてなんですが、これは呼ぶことができないのが常識ですよね。
なのですが、いろいろとやってみたところ、制限はあるものの、なんとかそれっぽいのが作れたんです。
しかし、本当にこのコードが間違ったことをしていないという自信がありません……。
そこで皆さんにお訊ねします。
このコードはセーフでしょうか?アウトでしょうか?

//----- ここから -----

#include <iostream>
struct CLS{
virtual void func()=0;
CLS(){}
template<class T> CLS(T*){reinterpret_cast<T*>(this)->T::func();}
};

struct CLS1:public CLS{
virtual void func(){ std::cout << "x";}
CLS1():CLS((CLS1*)0){}
template<class T> CLS1(T* x):CLS((T*)0){}
};

struct CLS2:public CLS1{
virtual void func(){}
CLS2():CLS1((CLS2*)0){std::cout<<"y";}
template<class T> CLS2(T*):CLS1((T*)0){}
};


int main(){
CLS* x = new CLS1;
CLS* y = new CLS2;
delete x;
delete y;
return 0;
}

//----- ここまで -----

C++の言語規約を読んだりとかはしていないので、自分では判断つきかねるのですが、コンパイラを通したところ、
cl g++ dmc bcc32
あたりで試して全て成功しています。(どのコンパイラでも、ということになるのかはわかりませんが。)
セーフかアウトか…、またその理由をお聞かせください。
暇なときでかまわないので、ご意見いただけたらと思います。

タイトルのとおり、C++のクラスで自分のクラスを継承した先の仮想関数をコンストラクタで呼ぶ方法についてなんですが、これは呼ぶことができないのが常識ですよね。
なのですが、いろいろとやってみたところ、制限はあるものの、なんとかそれっぽいのが作れたんです。
しかし、本当にこのコードが間違ったことをしていないという自信がありません……。
そこで皆さんにお訊ねします。
このコードはセーフでしょうか?アウトでしょうか?

//----- ここから -----

#include <iostream>
struct CLS{
virtua...続きを読む

Aベストアンサー

私も他の方と同様、「アウト」だと思います。

ISO/IEC14882だと12.7あたりで初期化完了してない云々に触れてます。
このコードはundefined behavior(未定義動作)なのでコンパイラにはエラーを検出する責務がありません。
# 当然、どのコンパイラでもそうなる保証なんてないですし、
# エラーを見つけてくれるとも限りません。(だからとりあえずそれっぽく動いて見えている)

実際、上記のコードをちょっと直して、問題をおこすのも簡単です。

 各クラスにメンバ変数を追加して、出力してみてください。

未定義動作として不正参照してるだけで初期化が完了してませんので、
単純に文字を出力してるだけだと気づかないかもしれませんが、
例えば手元のVC7.1で以下のコードを実行するとx,yともn1、n2がゴミになります。
これがご期待の動作でしょうか。(意図してメンバを参照しないコードを書いていますか?)
提示のサンプルはまだしも、未定義動作で言語仕様から逸脱した挙句に、
実際にはメンバすら触れないメソッドの呼び出しは何かうれしいですか?と私は思います。

また、reinterpret_castはポインタを補正をしてくれませんので、
仮想継承とかしてる場合はもっと致命的におかしなことになる可能性があります。
(これも意図して避けていますか?考慮されていないだけですか?)

まぁ、それでもundefined behaviorなので一見正しく動く環境はあるのかもしれませんが、
私ならやはり「アウト」だといいます。

#include <iostream>
struct CLS{
int n1;
virtual void func()=0;
CLS():n1(1){}
template<class T> CLS(T*){reinterpret_cast<T*>(this)->T::func();}
};

struct CLS1:public CLS{
int n2;
virtual void func(){ std::cout << "x" << n1 << ":" << n2<< std::endl;}
CLS1():CLS((CLS1*)0), n2(2){}
template<class T> CLS1(T* x):CLS((T*)0){}
};

struct CLS2:public CLS1{
int n3;
virtual void func(){}
CLS2():CLS1((CLS2*)0), n3(3){std::cout<< "y" << n1 << ":" << n2 << ":" << n3 << std::endl;}
template<class T> CLS2(T*):CLS1((T*)0){}
};


int main(){
CLS* x = new CLS1;
CLS* y = new CLS2;
delete x;
delete y;
return 0;
}

ちなみに、初期化順はもともとが記述順とは別に決まっているものなので、
仮にn3(3)等を前に書くとかしても無駄です。
# undefined behaviorなので「VC7.1で試しても変わりませんでした」が正しいか。

私も他の方と同様、「アウト」だと思います。

ISO/IEC14882だと12.7あたりで初期化完了してない云々に触れてます。
このコードはundefined behavior(未定義動作)なのでコンパイラにはエラーを検出する責務がありません。
# 当然、どのコンパイラでもそうなる保証なんてないですし、
# エラーを見つけてくれるとも限りません。(だからとりあえずそれっぽく動いて見えている)

実際、上記のコードをちょっと直して、問題をおこすのも簡単です。

 各クラスにメンバ変数を追加して、出力してみてください...続きを読む

Qc++からdll内の関数を呼ぶ記述方法が知りたいです。

VC++2008 Expressを使っています。
c++からdll内の関数を呼ぶ記述方法が知りたいです。

hoge.dllの関数
int test(int x);

c++
??????????

Aベストアンサー

手順としてはこんな感じになります。


// 関数の型宣言
typedef int (*PFUNC_TEST)(int);

// DLLをロード
HINSTANCE hDll = LoadLibrary("hoge.dll");

// 関数へのポインタを取り出す
PFUNC_TEST test = (PFUNC_TEST)GetProcAddress(hDll , "test");

// 関数を使う
int a = test(5);

// 最後にDLLを解放
FreeLibrary(hDll);


LoadLibrary関数とGetProcAddress関数は失敗するとNULLを返すので、そのチェックも必要です。

QC&C++からC#のexeを呼ぶ方法

いつもお世話になっております。

環境
Windows VISTA SP1
Visual Studio 2008

疑問
C(C++)からC#で作られたexeを呼ぶ方法がわかりません。
ret = CreateProcess(NULL,Common_Data->exename,NULL,NULL,FALSE,NORMAL_PRIORITY_CLASS,
NULL, NULL, &si, &pi);

の様にCreateProcessではexeを呼べません。
(Common_Data->exenameにはGetCurrentDirectory使って
絶対パス指定してます)

おそらくC#でつくったプロジェクトの設定を変えてビルド
する必要があると推測していますが
どうすればいいのかわからないです。

以上 よろしくお願いいたします。

Aベストアンサー

「CreateProcess error 998 ERROR_NOACCESS」
でぐぐってみたところ、以下のような情報がありました。
http://fujiyoshisyouta.blog72.fc2.com/blog-entry-209.html

STARTUPINFO構造体(si)は、正しく初期化してますか?
特に、si.cbにSTARTUPINFO構造体のサイズが正しく入っていないと、
今回のようなエラーを返却する可能性が高いと思います。

http://itpro.nikkeibp.co.jp/article/COLUMN/20070126/259762/
を参考にしてください。


このQ&Aを見た人がよく見るQ&A

このカテゴリの人気Q&Aランキング

おすすめ情報