Windows 環境、VSTS 2008 + C++ プロジェクトで確認したいのですが、extern C は関数レベルにしか適用できず、クラス レベルには適用できません (クラスのすべてのメンバー関数が C 言語名マングリングを使用するように)。いくつかの方法を試しましたが、常にコンパイル エラーが発生します。
前もって感謝します、ジョージ
Windows 環境、VSTS 2008 + C++ プロジェクトで確認したいのですが、extern C は関数レベルにしか適用できず、クラス レベルには適用できません (クラスのすべてのメンバー関数が C 言語名マングリングを使用するように)。いくつかの方法を試しましたが、常にコンパイル エラーが発生します。
前もって感謝します、ジョージ
extern "C"
非常に複雑な(しかし完全に合法的な)ハックを介して、メンバー関数に適用することができます。
extern "C" typedef int bar_t(int x);
struct foo {
bar_t bar; // yes, this declares a nonstatic member function!
};
int foo::bar(int x) { return x; } // definition
これは、ISO C++03 9.3[class.mfct]/9 に従って可能です。
メンバー関数は、関数型の typedef を使用して宣言できます (定義はできません)。結果のメンバー関数は、関数宣言子が明示的に提供された場合とまったく同じ型になります。8.3.5 を参照してください。
ただし、ISO C++03 7.5[dcl.link]/4 のため、これは実際には何も購入しません。
クラスメンバの名前とクラスメンバ関数のメンバ関数型については、AC 言語リンケージは無視されます。
以前の回答に寄せたコメントを見ると (「[私の] 質問は、クラス内のすべての関数が自動的に C スタイルの名前マングリングを持つように、クラス レベルで適用できるかどうかだけですextern C
。extern "C"
そのように働きなさい。
構文的にextern "C"
は、中括弧で区切られたブロックの単一のステートメントに適用できます。
extern "C" int my_foo(int i)
{
...
}
extern "C" {
int my_bar(int i)
{
...
}
int my_baz(int i)
{
...
}
}
C ヘッダー全体extern "C"
に適切なガードを付けて使用するのが一般的です。#ifdef __cplusplus
意味的には、適用の実際の効果は、extern "C"
「通常の」(つまり、非クラスの) 関数と関数へのポインタにのみ適用されます。もちろん、C++ テンプレートに適用することはできません。また、それをクラス メソッドに適用することもできません (クラス メソッドは、それが呼び出されたオブジェクトを知る必要があり、C スタイルのリンケージにはその情報を関数に渡す方法がないため)。
名前空間に存在する関数に適用することはextern "C"
可能ですが、C 経由で使用すると名前空間の情報が消えてしまいます。
すでにクラスがあり (簡単にするためにPOD クラスを使用します)、それを C から使用できるようにしたい場合は、C でextern "C"
呼び出し可能な関数に適用する必要があります。残念ながら、これは単純なケースでも見苦しくなります:
// in the header file
#ifdef __cplusplus
namespace X {
#endif
struct A
{
int x;
#ifdef __cplusplus
A() : x(5) { }
int foo()
{
return x += 5;
}
#endif
};
#ifdef __cplusplus
extern "C" {
#endif
int A_foo(struct A a);
struct A A_create();
#ifdef __cplusplus
}
}
#endif
// in the .cc file
#include "try.h"
namespace X {
extern "C" {
int A_foo(A* a)
{
return a.foo();
}
A A_create()
{
return A();
}
}
}
// in the .c file
#include <stdio.h>
#include "try.h"
int main()
{
struct A a = A_create();
printf("%d", A_foo(a));
}
gcc を使用すると、次のようにコンパイルできます。
g++ try.cc -c -o try.o
gcc try.c try.o
重要な点がいくつかあります。
new
or delete
(またはnew[]
or delete[]
) を呼び出す場合は、最終的なプログラムを C++ ランタイム ライブラリにリンクする必要があります (gcc でのコマンド ライン スイッチは-lstdc++
.デストラクタを明示的に呼び出すには:
extern "C" void A_destroy(struct A a)
{
a.~A();
}
うーん... extern "C"
C スタイルのリンケージを強制します。クラスAFAIKでは使用できません。