2016-11-25 4 views
11

でC++機能マングル名を取得する、のValueHolder :: printValue私はコンパイル時(または実行時)にそのマングルされた名前を確認するにはどうすればよい私は、関数、クラスメソッドを持ってコンパイル時(または実行時)

class ValueHolder { 

public: 
    void printValue(); 
} ; 

たとえば、私はこれをやりたい:前提条件は、現代のコンパイラです@Marco Aを1として

"_ZN11ValueHolder10printValueEv" 

const char *mangled_name = GetMangledNameOfSymbol(&ValueHolder::printValue); 

この関数は以下のように文字列を返すことがあります。 typeidをサポートし、フラグをオンにしてこの機能を有効にするもの。

また、GCC & ClangとMSVC用のスタブ用に実用的な答えを受け入れます。

答えて

-2

あなたができることは、g ++を使ってC++プログラムをコンパイルし、.oファイルを取得することです。このようにして得られた.oファイルに対して 'nm'コマンドを実行すると、名前が変更されます。この方法は、Linuxシステムで実行可能です。

8

クラスTYPE_INFOは実装によって生成された型情報を記述[lib.type.info]

によると、これを行うための標準的な方法はありません。このクラスのオブジェクトは、型の名前へのポインタと、等価または照合順序の2つの型の比較に適した符号化された値を効果的に格納します。タイプの名前、エンコーディングルール、照合順はすべて指定されておらず、プログラムによって異なる場合があります。

とコンパイラの実装に

あなたが typeid(type/expression).name()を使用することができますが、それはどこにも指定されていないか、この名前が飾られることが強制されます(それが 実装定義です)。これはまた、使用されたコンパイルフラグにも依存します(ママットに感謝します)。

例:

class ValueHolder { 

public: 
    void printValue(); 
}; 


int main() { 
    std::cout << typeid(&ValueHolder::printValue).name(); 
} 

gcc7.0

M11ValueHolderFvvE

clang4.0

M11ValueHolderFvvE

MSVC14

のボイド(__cdeclのValueHolder :: *)(無効)__ptr64

+0

も – malat

+0

(例えばSTD = C++ 11とstd ::文字列、および/または-DGLIBCXX_DEBUG' 'のようなもの)、それはコンパイラ+バージョンに依存するだけでなく、コンパイル時のフラグだけでなく、明確にしてください@ malatありがとう、私は答えにその作品を追加します。 –

+0

これはすばらしい答えです。最近のコンパイラを使って反映するために、ちょっとだけ質問を変えようと思っています。 – iamacomputer

3

私は答えを追加しますが、私は正しい、それをマークするつもりはありません。それは完全ではありません。コメントとして追加するには大きすぎます。これは私ができる行に沿ったものですが、より良い方法を探しています。そして、はい、非常にタッキーなハッキー。しかし、私はどこかでまだ少し粗くても、(プロジェクト全体で1つのコンパイラを使用すると)動作することが保証されているAPIがあると思います。

template<typename R, typename C, typename... A> 
struct MemberFunctionPointer 
{ 
    typedef R Return; 
    typedef C Class; 
}; 

template<typename R, typename C, typename... A> 
constexpr auto inferMemberFunctionPointer(R (C::*method)(A...)) 
{ 
    return MemberFunctionPointer<R,C,A...>{}; 
} 

template<typename M, M m, typename... A> 
class GenerateMethodSignature 
{ 
    typedef typename decltype(inferMemberFunctionPointer(m))::Class T; 
    typedef typename decltype(inferMemberFunctionPointer(m))::Return R; 


public: 
    static const char *mangledName (const char *fs) 
    { 
     const char *ts = typeid(T).name(); 
     const char *rs = typeid(R).name(); 
     const char *ms = typeid(M).name(); 

     std::string r = "_Z"; 
     if (ts[0] != 'N') 
      r += "N"; 
     r += ts; 
     if (ts[0] == 'N') 
      r.pop_back(); 

     r += std::to_string(strlen(fs)); 
     r += fs; 
     r += "E"; 

     r += ms + strlen ("M") + strlen(ts) + strlen ("F") + strlen(rs); 
     r.pop_back(); 

     printf("calculated signature %s\n", r.c_str()); 

     // this is very bad but... for demonstration purposes 
     return strdup(r.c_str()); 
    } 
} ; 

namespace MyNamespace { 
namespace MySubNamespace { 
class MyClass 
{ 
public: 
    int MyFunction (int myarg); 
} ; 
} // namespace 
} // namespace 

#define ExportSignature(T, M) GenerateMethodSignature<decltype(&T::M), &T::M>::mangledName(#M) 
const char *myMethodSignature = ExportSignature(MyNamespace::MySubNamespace::MyClass, MyFunction); 
+0

有望そうです。しかし、すべてのケースで正しく機能していないようです。 MyFunctionの戻り値の型をstd :: stringに変更してみてください。 – hedayat

+0

この場合、関数名にB5cxx11後置記号が追加されます。 また、パラメータのタイプをstd :: stringに変更すると、出力が完全にねじれてしまいます。 – hedayat

+0

この回答は完全ではなく、デモだけです。私は誰かがハッキーではなかったより良い方法を持つことを望んでいました。 – iamacomputer

関連する問題