最近面接を受けたのですが、C++ コードでの の使用法について質問されましたextern "C"
。C では名前マングリングを使用しないため、C++ コードで C 関数を使用するためだと答えました。C では名前マングリングを使用しない理由を尋ねられましたが、正直に言って答えられませんでした。
C++ コンパイラが関数をコンパイルするときに、主に C++ で同じ名前の関数をオーバーロードすることができ、コンパイル時に解決する必要があるため、関数に特別な名前を付けると理解しています。C では、関数の名前は同じままか、その前に _ が付く場合があります。
私の質問は、C++ コンパイラが C 関数も変更できるようにすることの何が問題なのかということです。コンパイラが関数にどのような名前を付けるかは問題ではないと私は考えていました。C と C++ では関数の呼び出し方法は同じです。
ベストアンサー1
上記である程度答えましたが、文脈に沿って説明してみたいと思います。
まず、C が先に登場しました。そのため、C が行うことは、ある意味「デフォルト」です。名前を改変しません。単にそうしないからです。関数名は関数名です。グローバルはグローバル、というように。
その後、C++ が登場しました。C++ は、C と同じリンカーを使用し、C で記述されたコードとリンクできるようにしたいと考えていました。しかし、C++ は C の「マングリング」(または、その欠如) をそのままにしておくことはできませんでした。次の例を確認してください。
int function(int a);
int function();
C++ では、これらは別個の関数であり、別個の本体を持ちます。どちらもマングルされていない場合、両方とも「function」(または「_function」) と呼ばれ、リンカーはシンボルの再定義についてエラーを発します。C++ の解決策は、引数の型を関数名にマングルすることでした。そのため、一方が呼び出され_function_int
、もう一方が呼び出され_function_void
(実際のマングル方式ではありません)、衝突が回避されます。
ここで問題が残ります。 がint function(int a)
C モジュールで定義されていて、そのヘッダー (つまり宣言) を C++ コードで取得して使用する場合、コンパイラは をインポートするようにリンカーに指示を生成します_function_int
。 関数が C モジュールで定義されたとき、その関数は と呼ばれていませんでした。 と呼ばれていました_function
。これにより、リンカー エラーが発生します。
このエラーを回避するには、宣言関数の最後に、その関数が C コンパイラにリンクされるか、C コンパイラによってコンパイルされるように設計された関数であることをコンパイラに伝えます。
extern "C" int function(int a);
C++ コンパイラは_function
ではなくをインポートすることを認識しており_function_int
、すべてが正常になります。