17

私はそのような例をBoostコードで見つけます。

namespace boost {
   namespace {
     extern "C" void *thread_proxy(void *f)
     {
       ....
     }

   } // anonymous
   void thread::thread_start(...)
   {
       ...
       pthread_create(something,0,&thread_proxy,something_else);
       ...
   }
} // boost

なぜ実際にこれが必要なのextern "C"ですか?

関数がプライベート内部であることは明らかであり、thread_proxy実際にはマングルする必要がまったくないため、「thread_proxy」としてマングルされることはないと思います。

実際、私が作成し、多くのプラットフォームで実行されるすべてのコードで、使用extern "C"したことはなく、これは通常の関数でそのまま機能していました。

なぜextern "C"追加されるのですか?


私の問題は、extern "C"関数がグローバル名前空間を汚染し、作成者が期待するように実際には隠されていないことです。

これは重複ではありません! 私はマングリングと外部リンケージについて話しているのではありません。このコードでは、外部リンケージが不要であることは明らかです。

回答: C関数とC ++関数の呼び出し規約は必ずしも同じではないため、Cの呼び出し規約を使用して作成する必要があります。C ++標準の7.5(p4)を参照してください。

4

6 に答える 6

17

関数がプライベートな内部であることは明らかであり、thread_proxy「thread_proxy」としてマングルされるとは思っていません。実際には、マングルする必要はまったくないからです。

とにかく、それはまだ台無しになるでしょう。(そうでなかったらextern "C") それがコンパイラの仕組みです。コンパイラが「これは必ずしもマングルする必要はない」と言う可能性があることに同意しますが、標準はそれについて何も述べていません。とはいえ、関数にリンクしようとしているわけではないので、マングリングはここでは関係ありません。

実際、私が書いた多くのプラットフォームで実行されるすべてのコードで、私は使用extern "C"したことがなく、これは通常の機能でそのまま機能していました。

異なるプラットフォームでの書き込みは、 とは関係ありませんextern "C"。標準 C++ 準拠のコンパイラを備えたすべてのプラットフォームで、すべての標準 C++ コードが動作することを期待しています。

extern "C"pthreadがライブラリであるCとのインターフェースに関係しています。名前を壊さないだけでなく、C 呼び出し規則で呼び出し可能であることを確認します。保証する必要があるのは呼び出し規約であり、特定のコンパイラ、プラットフォーム、またはアーキテクチャで実行しているとは想定できないため、それを試す最善の方法は、与えられた機能を使用することですextern "C"

私の問題は、extern "C"関数がグローバル名前空間を汚染し、作成者が期待するように実際には隠されていないことです。

上記のコードを汚染するものは何もありません。名前のない名前空間にあり、翻訳単位の外からはアクセスできません。

于 2010-04-07T16:37:53.800 に答える
6

extern "C"リンケージは、必ずしも名前のマングリングのみが抑制されることを意味するわけではありません。実際、別の呼び出し規約extern "C"として扱うコンパイラが存在する場合があります。

標準では、これを実装定義のセマンティクスとして完全にオープンのままにしています。

于 2010-04-07T16:37:47.667 に答える
5

質問は有効です。関数は C ライブラリに渡されていますが、その C ライブラリは C++ コードにまったくリンクしていません。関数のアドレスが与えられるだけなので、関数の名前にはまったく関心がありません。

ポイントはextern "C"、関数がそのプラットフォームで標準の C 呼び出し規則を使用するようにコンパイラーに指示するクロスプラットフォームの方法 (つまり、パラメーターと戻り値がスタック上でどのように渡されるか) に最も近いことです。

残念なことに、グローバル レベルで extern リンカー シンボルを作成するという副作用もあります。boost_detail_thread_proxyただし、これは代わりにlike という名前を使用することで軽減できます。

于 2010-04-07T16:42:55.907 に答える
1

__cdecl. _


それだけです。ここでの名前マングリング、名前空間、またはその他の奇妙な回答とはまったく関係ありません (質問したときに既に知っていたように)。

于 2010-04-07T17:07:56.253 に答える
0

C と C++ の呼び出し規約が同じであるとは限らないため、コールバック関数をC 関数extern "C"に渡すために宣言する必要があります。pthread_create

名前空間は関数に影響を与えないため、上記のthread_proxy関数には外部リンケージがあります (つまり、その翻訳単位の外に表示されます) extern "C"。匿名の名前空間であってもです。代わりに、関数に内部リンケージを与えるには、thread_proxy静的として宣言する必要があります。

namespace boost {
    namespace {
        extern "C" {
            static void *thread_proxy(void *f)
            {
                ....
            }
        } // extern "C"
    } // anonymous
    ...
} // boost

[編集] boost にはこの変更が組み込まれていることに注意してください。https://svn.boost.org/trac/boost/ticket/5170を参照してください。

于 2011-02-08T20:14:15.180 に答える
0

おそらく、プレーンな C ライブラリ (pthreads) とやり取りしているためです。

于 2010-04-07T16:35:06.833 に答える