2017-08-30 4 views
3

C互換関数(この場合は(int, int) -> int)を持つC++関数をCシンボルとしてエクスポートすることはできますか?あなたが気をつけなければならない隠された落書きがありますか?C++関数をextern "C"として再エクスポートするために関数を割り当てます。


次のコードは警告なしでコンパイルされ、結果ファイルには2つのシンボルが公開されています。

私はそれがまったくコンパイルされていることに驚きました。なぜなら、私は関数をコピーすることが何を意味するのか分からないからです。

namespace simplemath { 
    int add(int x, int y) { 
    return x + y; 
    } 
} 

extern "C" auto add = simplemath::add; 

$ clang++ -Wall -Werror -pedantic --std=c++11 -c example.cc 
$ nm example.o 
0000000000000000 T __ZN10simplemath3addEii 
0000000000000018 D _add 

下記(simplemath::addか否かがインライン化さまで)に相当する上記のコードはありますか?あなたは

$ clang++ -Wall -Werror -pedantic -c example.cc 
$ nm example.o 
0000000000000020 T __ZN10simplemath3addEii 
0000000000000000 T _add 
+1

最初の例は、関数がオーバーロードされていない場合にのみ機能します – NathanOliver

答えて

5

いいえ、これは一般的には機能しません。 Cリンケージを持つ関数とC++リンケージを持つ関数は、同じ型を取り、同じ型を返す場合でも、型が異なります。したがって、関数ポインタの代入は合法ではありません。しかし、ほとんどのコンパイラはこれを強制するわけではありません。もちろん、ここで正しいセマンティクスを強制するコンパイラにアップグレードすると、すぐにコードが破損します。

多くの人が、CとC++のリンケージの違いを誤解しています。それは単なるネームマングリングの問題だと思います。しかし、それ以上です。たとえば、コンパイラは2つの異なるリンケージに対して異なる呼び出し規約を使用できます。その場合、CコードでC++関数へのポインタを使用する方法はありません。 extern "C"は、コンパイラにをコンパイルすると、Cから呼び出せるように関数をコンパイルします。

3

を取得

extern "C" int add(int x, int y) { 
    return simplemath::add(x, y); 
} 

namespace simplemath { 
    int add(int x, int y) { 
    return x + y; 
    } 
} 

最初のバージョンは、本当に(あなたがそれを行うことはできません)関数をコピーするのではなく、関数へのポインタを作成しません。

コンパイラがCおよびC++関数に同じ呼び出し規約を使用している場合は、おそらくこれが機能する可能性があります。そうでなければコンパイルに失敗するかもしれませんが、わかりません。

とにかく、私はラッパー関数を作成するための意図された方法であり、より移植性が高いので、2番目のバージョンを使用します。 extern "C"関数のパラメータを「再パック」することにより、関数が正しく渡されたことがわかります。

関連する問題