std::type_info::name の結果をアンマングリングする 質問する

std::type_info::name の結果をアンマングリングする 質問する

私は現在、呼び出し関数に関する情報を出力することなどを想定したログ コードを作成中です。これは比較的簡単なはずです。標準 C++ にはクラスがありますtype_info。これには、typeid されたクラス/関数などの名前が含まれていますが、文字化けしています。あまり役に立ちません。つまり、typeid(std::vector<int>).name()を返しますSt6vectorIiSaIiEE

これから何か役に立つものを作る方法はありますか?std::vector<int>上記の例のように。それが非テンプレート クラスでのみ機能するのであれば、それも問題ありません。

このソリューションは gcc でも機能するはずですが、移植できればもっと良いでしょう。これはログ記録用なので、オフにできないほど重要ではありませんが、デバッグには役立つはずです。

ベストアンサー1

この質問/回答が注目を集め、貴重なフィードバックをいただいたことを考えると、GマンニックGコードを少し整理しました。C++11 の機能を備えたバージョンと C++98 の機能のみを備えたバージョンの 2 つが提供されています。

ファイル内タイプ.hpp

#ifndef TYPE_HPP
#define TYPE_HPP

#include <string>
#include <typeinfo>

std::string demangle(const char* name);

template <class T>
std::string type(const T& t) {

    return demangle(typeid(t).name());
}

#endif

ファイル内タイプ.cpp(C++11 が必要)

#include "type.hpp"
#ifdef __GNUG__
#include <cstdlib>
#include <memory>
#include <cxxabi.h>

std::string demangle(const char* name) {

    int status = -4; // some arbitrary value to eliminate the compiler warning

    // enable c++11 by passing the flag -std=c++11 to g++
    std::unique_ptr<char, void(*)(void*)> res {
        abi::__cxa_demangle(name, NULL, NULL, &status),
        std::free
    };

    return (status==0) ? res.get() : name ;
}

#else

// does nothing if not g++
std::string demangle(const char* name) {
    return name;
}

#endif

使用法:

#include <iostream>
#include "type.hpp"

struct Base { virtual ~Base() {} };

struct Derived : public Base { };

int main() {

    Base* ptr_base = new Derived(); // Please use smart pointers in YOUR code!

    std::cout << "Type of ptr_base: " << type(ptr_base) << std::endl;

    std::cout << "Type of pointee: " << type(*ptr_base) << std::endl;

    delete ptr_base;
}

次のように印刷されます:

ptr_base の型:Base*
ポインタの型:Derived

Linux 64 ビットおよび g++ 4.7.2 (Mingw32、Win32 XP SP2) 上の g++ 4.7.2、g++ 4.9.0 20140302 (実験的)、clang++ 3.4 (trunk 184647)、clang 3.5 (trunk 202594) でテスト済み。

C++11の機能を使用できない場合は、C++98でこれを行う方法があります。ファイルタイプ.cpp今でしょ:

#include "type.hpp"
#ifdef __GNUG__
#include <cstdlib>
#include <memory>
#include <cxxabi.h>

struct handle {
    char* p;
    handle(char* ptr) : p(ptr) { }
    ~handle() { std::free(p); }
};

std::string demangle(const char* name) {

    int status = -4; // some arbitrary value to eliminate the compiler warning

    handle result( abi::__cxa_demangle(name, NULL, NULL, &status) );

    return (status==0) ? result.p : name ;
}

#else

// does nothing if not g++
std::string demangle(const char* name) {
    return name;
}

#endif


(2013年9月8日更新)

受け入れられた回答(2013年9月7日現在)への呼び出しがabi::__cxa_demangle()成功すると、ローカルのスタックに割り当てられた配列へのポインタを返します。... 痛い!
また、バッファを提供する場合は、abi::__cxa_demangle()ヒープ上に割り当てられるものと想定されることに注意してください。スタック上にバッファを割り当てるのはバグです(GNU ドキュメントより)。output_bufferが十分長くない場合は、 を使用して拡張されますrealloc。」 realloc()スタックへのポインタを呼び出す...痛い!(こちらも参照)イゴール・スコチンスキーの優しいコメントです。

これらのバグはどちらも簡単に確認できます。承認された回答(2013年9月7日現在)のバッファサイズを1024から16などのより小さな値に減らし、名前を付けるだけです。ない15以上(realloc()つまりない呼び出されます)。それでも、システムとコンパイラの最適化によっては、出力はゴミ / 何も出力されない / プログラムがクラッシュするなどになります。2番目のバグを確認するには、バッファ サイズを 1 に設定し、名前が 1 文字より長いもので呼び出します。実行すると、スタックへのポインターで
呼び出そうとするため、プログラムはほぼ確実にクラッシュします。realloc()


(2010年12月27日の古い回答)

重要な変更点KeithBのコード:バッファは malloc によって割り当てられるか、NULL として指定される必要があります。スタック上に割り当てないでください。

そのステータスも確認しておくのが賢明です。

見つけられませんでしたHAVE_CXA_DEMANGLE。確認しました__GNUG__が、コードがコンパイルされることは保証されません。もっと良いアイデアをお持ちの方はいらっしゃいますか?

#include <cxxabi.h>

const string demangle(const char* name) {

    int status = -4;

    char* res = abi::__cxa_demangle(name, NULL, NULL, &status);

    const char* const demangled_name = (status==0)?res:name;

    string ret_val(demangled_name);

    free(res);

    return ret_val;
}

おすすめ記事