17

extern "C"関数は、C++ 固有のデータ型 (参照、メンバーへのポインター、または非 POD クラス (値渡し) など) を受け入れたり返したりできますか? これを禁止するC++標準には何も見つかりません。論理的には、C ABI がそのような型を渡すのに必ずしも適しているとは限らないため、標準がそれについて何かを言うことを期待しています。

私が C リンケージを使用したい理由は、C コンパイラとは関係ありません。この関数は、C++ コードからのみ呼び出されます。動的ライブラリからマングルされていない関数名をエクスポートしたいだけです。

愚かなコード例:

class Foo {
  public:
    virtual void doit() = 0;
};

class Bar : public Foo {
  public:
    void doit() { std::cout << "Bar" << std::endl; }
};

extern "C" Foo& getFoo() { static Bar bar; return bar; }

extern "C" Bar getBar() { return Bar(); }

これは Linux 上の GCC でコンパイルされ、期待どおりに動作します。それは、標準的にすべきですか?

この質問は、この質問へのコメントでの議論のフォローアップです。

更新これを Comeau コンパイラでテストしましたが、問題はありませんでした。

4

4 に答える 4

8

セクション7.5.9リンケージ仕様(c ++ 11ドラフト)によるとhttp://www.open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3242.pdf

「C++から他の言語で定義されたオブジェクトおよび他の言語からC++で定義されたオブジェクトへのリンクは、実装によって定義され、言語に依存します。2つの言語実装のオブジェクトレイアウト戦略が十分に類似している場合にのみ、そのようなリンクを実現できます。」

于 2012-01-20T22:46:06.160 に答える
4

5.2.2関数呼び出し[expr.call]

関数呼び出しには、通常の関数呼び出しとメンバー関数62(9.3)呼び出しの2種類があります。関数呼び出しは、後置式の後に、関数の引数を構成する式の空のコンマ区切りリストを含む括弧が続きます。通常の関数呼び出しの場合、後置式は、関数を参照する左辺値(この場合、関数からポインターへの標準変換(4.3)は後置式で抑制されます)、または関数型へのポインターを持つ必要があります。 。呼び出された関数の定義の関数型の言語リンケージとは異なる関数タイプの言語リンケージを持つ式を介して関数を呼び出すことは未定義です(7.5)

したがって、呼び出しポイントでの関数のタイプ(つまり、呼び出している関数のタイプ)が定義ポイントでの関数のタイプと異なる場合、結果は未定義です。

7.5リンケージ仕様(パラグラフ1)[dcl.link]

すべての関数型、外部リンケージのある関数名、および外部リンケージのある変数名には、言語リンケージがあります。

このことから、言語リンケージが関数のタイプの一部であることがわかります。したがって、コールサイトとコール実装の両方がまったく同じ言語リンケージを持っている必要があります。

7.5リンケージ仕様(パラグラフ9)[dcl.link]

C ++から他の言語で定義されたオブジェクト、および他の言語からC ++で定義されたオブジェクトへのリンクは、実装定義であり、言語に依存します。2つの言語実装のオブジェクトレイアウト戦略が十分に類似している場合にのみ、そのようなリンクを実現できます。

CはC++型をサポートしていないため、意味のある方法でC++オブジェクトをインターフェイスに渡すことはできません。この関数はC言語リンケージを持つことができず、C++オブジェクトを渡すことはできません。したがって、上記で定義されたタイプルールに違反しています。

ただし、オブジェクトのレイアウトだけでなく、オブジェクトがどのように渡されるか、または返されるかを考慮する必要があります。値はスタックまたはレジスタによって渡されますか?これはすべてABIによって定義され、C / C ++には異なるAPIがあるため、オブジェクトが一方から他方に渡される方法や、関数のクリーンアップの期待が同じであるという保証はありません。

于 2012-01-20T23:27:20.850 に答える
1

これに対する明確な答えはありませんが、ウィキペディアから推定すると、これが機能することは保証されていません。記事(私は標準のコピーを持っていません)はextern "C"、マングリングとABIの両方の仕様を述べています。C ABIはおそらく非Cタイプを指定していないので、指定されていない動作をします。(この記事では、CとC ++のABIが異なる場合も引用していますが、ここでは問題にはならないようです。)

ですから、事実上すべての場合に機能するかもしれないと思いますが、それが必要であると言っている基準から章と節を引用できるとは思えません。コンパイラがコンパイルを拒否したのを見て、私はそれほど驚かないでしょう。

于 2012-01-20T22:15:19.353 に答える
1

動的ライブラリからマングルされていない関数名をエクスポートしたいだけです。

装飾された名前付き関数を別の名前でエクスポートできる .def ファイルの使用を検討しましたか? このようにして、オーバーロードの利点を享受すると同時に、関数に好きなように「わかりやすい」名前を付けることができます。

EXPORTS
funcOfInt=?func@a@@AAEXH@Z
funcOfSomethingElse=?func@a@@XYZ@W
于 2012-01-20T23:42:04.010 に答える