Cプログラミング
 Computer >> コンピューター >  >> プログラミング >> Cプログラミング

C++の名前マングリング(Name Mangling)と extern "C" の仕組みを徹底解説

C++には関数オーバーロードという便利な機能があります。この機能を使うと、同じ名前の関数を複数定義できます。ただし、引数の型や引数の数が異なっている必要があり、戻り値の型の違いだけではオーバーロードとして認識されません。

ここで疑問が生じます。「C++は、オブジェクトコードの中でどのようにオーバーロードされた関数を区別しているのか?」という点です。

名前マングリングとは何か?

答えは、オブジェクトコードを生成する際に、引数の型情報などを関数名に付加して名前を変換している、というものです。この技術は名前マングリング(Name Mangling)と呼ばれます。

重要なポイントとして、C++には名前マングリングの標準規格が存在しないため、コンパイラによって実装方法が異なります。そのため、同じソースコードでも、使用するコンパイラによって生成されるシンボル名が変わることがあります。

名前マングリングの具体例

以下の例では、func()という同名のオーバーロード関数と、my_function()という別の関数を定義しています。

int func(int x) {
    return x*x;
}
double func(double x) {
    return x*x;
}
void my_function(void) {
    int x = func(2);      // int型のバージョンを呼び出し
    double y = func(2.58); // double型のバージョンを呼び出し
}

一部のC++コンパイラでは、上記のコードが内部的に次のような形に変換されます。

int __func_i(int x) {
    return x*x;
}
double __func_d(double x) {
    return x*x;
}
void __my_function_v(void) {
    int x = __func_i(2);
    double y = __func_d(2.58);
}

このように、関数名に引数の型を表す接尾辞(_i_d など)が付加され、シンボル名が一意になることで、リンカが正しい関数を参照できるようになっています。

C言語とのリンクで発生する問題

C言語は関数オーバーロードをサポートしていません。そのため、C++からC言語のコードをリンクする場合、シンボル名がマングリングされないように注意する必要があります

例えば、以下のようなC++コードはエラーになります。

int printf(const char *format,...);
main() {
    printf("Hello World");
}

出力結果(エラー)

undefined reference to `printf(char const*, ...)'
ld returned 1 exit status

このエラーが発生する原因は、コンパイラがprintf()という名前をマングリングしてしまうことにあります。その結果、リンカが変換後の名前に対応する関数の定義を見つけられず、「未定義参照(undefined reference)」エラーとなってしまうのです。

extern "C" による解決策

この問題を回避するために、C++ではextern "C" を使用します。extern "C" ブロック内に記述されたコードは、C++コンパイラによって名前マングリングが行われないことが保証されます。つまり、関数名は元のまま維持されます。

先ほどの問題のあるコードは、次のように修正することで正常に動作します。

extern "C" {
    int printf(const char *format,...);
}
main() {
    printf("Hello World");
}

出力結果

Hello World

まとめ

  • C++は関数オーバーロードを実現するため、引数の型情報を関数名に付加する「名前マングリング」を行う
  • 名前マングリングの方式は標準化されておらず、コンパイラごとに異なる
  • C言語のコードとリンクする際は、extern "C" を使ってマングリングを無効化する必要がある

注意: 名前マングリングの具体的な形式はコンパイラ依存のため、ここで紹介したコード例は、使用するコンパイラによって異なる結果になる場合があります。

  1. C++とC#の違いとは?メモリ管理・実行速度・継承などを徹底比較

    C++とはC++は、静的型付けのコンパイル型言語であり、大文字と小文字を区別する自由形式の汎用プログラミング言語です。手続き型・オブジェクト指向・ジェネリックといった複数のプログラミングパラダイムをサポートしており、OSやゲームエンジン、組み込みシステムなど幅広い分野で活用されています。C++は、高水準言語の生産性と低水準言語ならではのハードウェア制御能力を兼ね備えていることから、「中級言語(ミドルレベル言語)」と位置づけられることもあります。C#とはC#は、マイクロソフトがアンダース・ヘルスバーグ(Anders Hejlsberg)の主導のもと、.NET構想の一環として開発した、シンプルでモ

  2. C++とC#におけるforeachループの使い方を徹底解説

    コレクションや配列の各要素を順番に処理したい場合、foreachループは非常に便利な構文です。従来のforループではインデックスの管理が必要でしたが、foreachを使えば要素そのものを直接取り出して処理できるため、コードがシンプルになり、バグも減らせます。この記事では、C++とC#それぞれにおけるforeachの書き方と実行例をわかりやすく解説します。 C++におけるforeach(範囲ベースforループ) C++には厳密には「foreach」という名前のキーワードは存在しませんが、C++11で導入された範囲ベースforループ(range-based for loop)が同等の機能を提供し