1. ホーム
  2. c++

[解決済み] なぜCの関数は名前解決ができないのか?

2022-05-29 14:27:24

質問

最近面接を受けたのですが、そのときに聞かれた質問のひとつが extern "C" をC++のコードで使うことです。私は、Cは名前解決を使わないので、C++のコードでCの関数を使うためですと答えました。なぜCはname-manglingを使わないのかと聞かれましたが、正直言って答えられませんでした。

C++コンパイラが関数をコンパイルするとき、関数に特別な名前を付けるのは、主に、C++では同じ名前のオーバーロードされた関数があり、コンパイル時に解決しなければならないからだと理解しています。C では、関数の名前は同じままか、おそらくその前に _ が付きます。

私の疑問は、C++ コンパイラーが C の関数をも混乱させることを許可することの何が問題なのか、ということです。私は、コンパイラーがどのような名前を付けるかは問題ではないと考えていました。私たちは C と C++ で同じように関数を呼びます。

どのように解決するのですか?

上記で回答があったようなものですが、文脈を整理してみます。

まず、Cが最初に来ました。そのため、C が行うことは、ある意味、デフォルトのようなものです。なぜなら、C は名前を混乱させないからです。関数名は関数名です。グローバルはグローバル、といった具合です。

その後、C++が登場しました。C++はCと同じリンカーを使い、Cで書かれたコードとリンクできるようにしたかったのですが、C++はCのquot;mangling"(またはその欠如)をそのままにしておくことができませんでした。次の例を見てください。

int function(int a);
int function();

C++では、これらは異なる本体を持つ、異なる関数です。もしどれもマングルされていなければ、両方とも "function" (または "_function") と呼ばれ、リンカーはシンボルの再定義について不満を漏らすでしょう。C++の解決策は、引数の型を関数名の中に紛れ込ませることでした。つまり、1つは _function_int で、もうひとつは _function_void (というように変更すると、衝突が回避されます。

さて、問題が残りました。もし int function(int a) が C モジュールで定義されていて、C++ コードでそのヘッダ (つまり宣言) を取ってきて使っているだけなら、コンパイラはリンカにインポートするように命令を生成します。 _function_int . この関数が定義されたとき、Cモジュールではそのように呼ばれなかった。それは _function . これはリンカエラーの原因となります。

このエラーを回避するために 宣言 で、コンパイラにそれが C コンパイラとリンクされたり、コンパイルされたりするように設計された関数であることを伝えます。

extern "C" int function(int a);

C++コンパイラは、インポートするために _function よりも _function_int に変更すれば、すべてうまくいきます。