16.3 マングリング

C++プログラムをコンパイルする段階でマングリングという処理がされます。

「16.2 エントリポイント」で取り上げたC言語のコードをエントリポイントを指定してコンパイルしましょう。

#include<stdio.h>
int hoge()
{
    puts("hoge only");
}
gcc -e hoge() a.c

コンパイルに成功します。さて、では上記のC言語コードを、下記のように少し改変してコンパイルを行って見ましょう。

#include<cstdio>
int hoge()
{
    std::puts("hoge only");
}

int hoge(int){}
g++ -e hoge() a.c

私の環境では以下のようなエラーが出力されました。

2 warnings generated.
Undefined symbols for architecture x86_64:
  "hoge", referenced from:
     implicit entry/start for main executable
     (maybe you meant: __Z4hogei, __Z4hogev )
ld: symbol(s) not found for architecture x86_64

何やら、__Z4hogei__Zhogevというようなhogeというものを意味していますか?といったような内容が出力されました。ここでは__Zhogevを指定してみましょう。

g++ -e __Z4hogev a.cpp

これで、正しくコンパイルされました。実行結果も意図した通り、うまくいくようです。

hoge only

というようにC言語では関数名をそのまま指定するだけでエントリポイントを指定できていましたがC++言語では失敗してしまいました。何故でしょうか。

それはC言語の場合とは異なり、C++では、同じ名前を持つ関数が複数存在することが有りうるという事に帰結します(関数のオーバーロード、名前空間の異なる同名の関数、クラスごとのメンバ関数など)。

C++コンパイラは、それらの同名の関数をそれぞれ適切に識別するために、シグネチャや名前空間などをラベルに付加して埋め込みます。このような動作をマングリングといいます。このマングリングという動作によって、同名の関数を呼び分ける事ができます。

ラベルとして埋め込むのはシグネチャや名前空間です。マングリングの作用から関数のオーバーロードを考察すると、同じ名前空間上、あるいは同じクラススコープ上の中で、戻り値型だけが異なる関数同士はオーバーロードする事ができない理由が明白ですね。