11

通常の関数では、次のように書くことができます

extern "C" int Frotz(int);  // in a header

int Frotz(int x) { return x; }

ただし、関数ポインターでは、これはコンパイラー間で矛盾して実装されているようです。

extern "C" int Klutz(int (*)(int), int);

int Klutz(int (*fptr)(int), int x) { return (*fptr)(x); }

宣言では、引数もextern "C"です。定義では、ほとんどのコンパイラはこれらの関数に一致して関数を作成しているように見えKlutzますextern "C"。ただし、Sun および Cray コンパイラはこれらの関数を異なるものとして解釈し、オーバーロードint Klutz(int (*fptr)(int), int x)された を生成し、後でリンク時エラーを生成します。

C++98 および C++11 のセクション 7.5.5 では の解釈が保証されていますが、オーバーロードのチェックの前または後にマッチングを行うべきFrotzかどうかについて、標準が曖昧であるかどうかはわかりません。extern "C"

Klutz上記はマングル (C++) シンボルまたはシンボルを生成する必要がありextern "C"ますか?

編集1

C または C++ ABI を持つ関数ポインターのあいまいさを解消するために typedef を使用できますが、ここでのコードが (a) KlutzC++ リンケージを持つように定義するか、(b) C リンケージを持つように定義するか、または (c)標準によればあいまいなので、コンパイラはそれを解釈する方法を自由に選択できます。

編集2

これは、少なくとも検索可能なバグ トラッカーを備えたコンパイラでは、既知の問題のようです。私のテストでは、GCC、Clang、Intel、MSVC、IBM XL、PathScale、PGI、および Open64 はすべて、標準で明示的に要求されているように、言語リンケージを除いて同一の関数型を区別できません (セクション 7.5.1 を参照してください。受け入れられた答え)。これを修正すると、多くの既存のコードが壊れ、ABI の変更が必要になります。C言語とC++言語のリンケージに異なる呼び出し規約を実際に使用しているコンパイラは知りません。

  • GCC のバグ: 「次の標準からこの機能を削除することを要求する理由を見つけることは、一種の関連性があります ;-)」 ... 「そして、公式の WONTFIX を決定することさえあります。」

  • Clangのバグ : 「この規則を実際に適用するのが怖いです。適切に実行すると、言語リンケージが正規型の一部になり、大量のコードが壊れてしまうからです。」

4

1 に答える 1

8

CABIとC++ABIが同じであるとは限りません。したがって、extern "C"関数ポインタはC++関数ポインタとは異なるタイプです。次のようなものが必要です。

extern "C" {
    typedef int (*KlutzFuncType)(int);
    int Klutz (KlutzFuncType, int);
}

int Klutz (KlutzFuncType fptr, int x) { return (*fptr)(x); }

この問題についての議論がここにあります。


ドラフトのコピーしか持っていません。7.5p1から:

言語リンケージが異なる2つの関数型は、他の点では同一であっても、別個の型です。

私がこれを読んだのは、最初のパラメーターのKlutzタイプが2番目のパラメーターの最初のパラメーターとは異なるKlutzため、2番目のパラメーターにKlutzはC++リンケージが必要であるということです。


標準で述べられていることにもかかわらず、関数型の言語リンケージを考慮しないC++実装があります。次のコードスニペットでKlutzCxxFuncTypeは、C ++リンケージを持つ関数をKlutzCFuncType指し、Cリンケージを持つ関数を指します。

typedef int (*KlutzCxxFuncType)(int);

extern "C" {
    typedef int (*KlutzCFuncType)(int);
    int Klutz (KlutzCFuncType, int);
}

int Klutz (KlutzCxxFuncType fptr, int x) { return (*fptr)(x); }
int Klutz (KlutzCFuncType fptr, int x) { return (*fptr)(x); }

言語リンケージに基づいて関数型を区別しないコンパイラは、このコードで再定義エラーを生成します。たとえば、g++ 4.7.2次を放出します。

prog.cpp: In function ‘int Klutz(KlutzCFuncType, int)’:
prog.cpp:9:5: error: redefinition of ‘int Klutz(KlutzCFuncType, int)’
prog.cpp:8:5: error: ‘int Klutz(KlutzCxxFuncType, int)’ previously defined here
于 2013-03-20T23:38:16.530 に答える