Cpp 名前マングリング

提供:yonewiki

C++に戻る


本来の表記は「C++ 名前マングリング」です。この記事に付けられた題名はテンプレート:記事名の制約から不正確なものとなっています。

※このページではC++にのみ存在する機能として、記事タイトルがC++ 名前マングリングになっています。

名前マングリング

 名前マングリング(Name Mangling)は、C++コンパイラが関数や変数の名前を修飾し、異なるスコープや型に対して一意の名前を生成するプロセスです。C++では関数のオーバーロード、名前空間、クラス、テンプレートなどが名前マングリングの対象となります。これにより、同じ名前の関数でも引数の型や個数が異なれば異なるマングルされた名前が生成されます。


名前マングリングの例:  例えば、以下のようなC++のコードがあるとします:

namespace MyNamespace {
    class MyClass {
    public:
        void myFunction(int x);
    };
}

void globalFunction(double y);


これをコンパイルすると、名前マングリングが適用されます。実際に生成される名前はコンパイラやプラットフォームによって異なりますが、例えば次のような形になる可能性があります:


?myFunction@MyNamespace@MyClass@@QAEXH@Z
?globalFunction@@YAXN@Z


DLLやLibファイルの呼び出しでの名前マングリングの取り扱い:

 DLLやLibファイルの呼び出しにおいて、マングリングの取り扱いは重要です。異なるコンパイラや言語間でライブラリを共有する場合、名前マングリングが統一されていないと正しく関数を呼び出せません。

 

C++関数をCスタイルにエクスポートする方法

 一般的な方法として、C++関数をCスタイルにエクスポートする方法があります。これには extern "C" を使用します。関数の宣言だけでいいのです。関数の実体にはC++のコードを記述してよいので、関数名だけをC言語で表記することの弊害はほとんどありません。


extern "C" を使用する利点:

#ifdef __cplusplus
extern "C" {
#endif

void myFunction(int x);

#ifdef __cplusplus
}
#endif


 extern "C" ブロック内の関数はCスタイルの名前マングリングが適用され、C++の名前マングリングが無効になります。これにより、他の言語やC言語から直接呼び出すことが容易になります。


利点:

言語間の相互運用性: C言語は名前マングリングを行わないため、extern "C" を使用するとC++関数をC言語から利用しやすくなります。


DLLのエクスポート: WindowsのDLLでは、extern "C" を使用してエクスポートされた関数は名前マングリングが適用されません。これにより、DLL関数の名前が予測可能になります。


ヘッダーファイルの共有: C++関数を含むヘッダーファイルを他のプログラム言語で利用する場合、extern "C" を使って名前マングリングを無効にすると、他の言語で関数を呼び出しやすくなります。


 名前マングリングはコンパイラやプラットフォームに依存するため、言語間の相互運用性を確保するためにextern "C" を使用することは一般的なプラクティスです。

 

C++関数をC++スタイルの(名前マングリングを有効の)ままエクスポートする方法

 滅多にする人はいませんが、DLLを自分が使っているコンパイラだけ、同じ名前空間でだけ呼び出せる仕組みにしたい場合は名前マングリングを有効にしたまま、以下のようにプログラムを組んでもいいわけです。試しに一回くらいはやって確かめておいたら経験にはなると思います。


 C++の名前マングリングは、関数のシグネチャやスコープに基づいて行われるため、名前空間が一致していれば関数名も一致します。ただし、名前マングリングの詳細はコンパイラやプラットフォームに依存しており、一般的には同じ関数であっても異なる名前にマングリングされる可能性があります。そのため、名前マングリングが異なる場合、関数名が一致しない可能性があります。


 以下は、名前空間が一致する場合の例です。sampledll.cppはdllを出力するプロジェクト設定になっている必要があります。各種設定はVisualStudioのdll作成のテンプレート設定に従ってください。


DLL側の関数 (sampledll.cpp):

#include <iostream>
#include "sampledll.h"

namespace MyNamespace {
    void myFunction(int x) {
        std::cout << "DLL Function called with argument: " << x << std::endl;
    }
}

BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     )
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
        break;
    }
    return TRUE;
}


DLLのエクスポート (sampledll.h):

namespace MyNamespace {
    // DLL関数のエクスポート
    void myFunction(int x);
}


DLLを利用するC++プログラム (main.cpp):

#include <windows.h> // Windows用のDLL関連ヘッダー
#include <iostream>

namespace MyNamespace {
    // DLL関数の宣言
    void myFunction(int x);
}

int main() {
    // DLL関数の呼び出し
    MyNamespace::myFunction(42);

    return 0;
}


 

C++に戻る