문제

저는 현재 무엇보다도 호출 함수에 대한 정보를 인쇄하는 일부 로깅 코드를 작업 중입니다.이는 상대적으로 쉬울 것입니다. 표준 C++에는 type_info 수업.여기에는 유형 ID가 지정된 클래스/함수/등의 이름이 포함됩니다.하지만 망가졌어.별로 유용하지 않습니다.즉. typeid(std::vector<int>).name() 보고 St6vectorIiSaIiEE.

이것으로부터 유용한 것을 생산할 수 있는 방법이 있나요?좋다 std::vector<int> 위의 예에서는.템플릿이 아닌 클래스에서만 작동한다면 그것도 괜찮습니다.

솔루션은 gcc에서 작동해야 하지만 이식할 수 있다면 더 좋을 것입니다.로깅을 위한 것이므로 끌 수 없을 만큼 중요하지는 않지만 디버깅에는 도움이 될 것입니다.

도움이 되었습니까?

해결책

이 질문/답변이 주목을 받고 있으며, GManNickG, 코드를 조금 정리했습니다.두 가지 버전이 제공됩니다:하나는 C++11 기능이 있고 다른 하나는 C++98 기능만 있습니다.

파일에 있음 type.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

파일에 있음 type.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(트렁크 184647), clang 3.5(트렁크 202594)로 테스트되었습니다.

C++11 기능을 사용할 수 없는 경우 C++98에서 수행할 수 있는 방법은 다음과 같습니다. type.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() ~이다 ~ 아니다 라고 불리는).그러나 시스템 및 컴파일러 최적화에 따라 출력은 다음과 같습니다.쓰레기 / 아무것도 / 프로그램 충돌.
두 번째 버그를 확인하려면:버퍼 크기를 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;
}

다른 팁

Boost Core에는 Demangler가 포함되어 있습니다. 점검 Core/Demangle.hpp:

#include <boost/core/demangle.hpp>
#include <typeinfo>
#include <iostream>

template<class T> struct X
{
};

int main()
{
    char const * name = typeid( X<int> ).name();

    std::cout << name << std::endl; // prints 1XIiE
    std::cout << boost::core::demangle( name ) << std::endl; // prints X<int>
}

기본적으로 래퍼 일뿐입니다 abi::__cxa_demangle, 이전에 제안 된 바와 같이.

이것이 우리가 사용하는 것입니다. HAS_CXA_DEMANGL은 사용 가능한 경우에만 설정됩니다 (최근 버전의 GCC 만 해당).

#ifdef HAVE_CXA_DEMANGLE
const char* demangle(const char* name)
{
   char buf[1024];
    unsigned int size=1024;
    int status;
    char* res = abi::__cxa_demangle (name,
                                 buf,
                                 &size,
                                 &status);
    return res;
  }
#else
const char* demangle(const char* name)
{
  return name;
}
#endif  

여기서 살펴보십시오 type_strings.hpp 원하는 것을 수행하는 함수가 포함되어 있습니다.

로그 파일에 표시된 물건을 맹글하는 데 사용할 수있는 Demangling 도구를 찾으십시오. c++filt, Binutils와 함께 제공됩니다. C ++ 및 Java 기호 이름을 demangle 할 수 있습니다.

완전한 해결책은 아니지만 표준 (또는 널리 지원되는) 매크로의 정의를보고 싶을 수도 있습니다. 로깅 코드에서는 매크로의 사용을 보는 것이 일반적입니다.

__FUNCTION__
__FILE__
__LINE__

e.g.:

log(__FILE__, __LINE__, __FUNCTION__, mymessage);

구현이 정의되어 있으므로 휴대용이 아닙니다. MSVC ++에서는 이름 ()이 미색 이름이며, 장식 된 이름을 얻으려면 raw_name ()을 살펴 봐야합니다.
여기 어둠 속에서 찌르지 만 GCC 아래에서보고 싶을 수도 있습니다. demangle.h

나는 또한 매크로라고 불렀다 __PRETTY_FUNCTION__, 그것은 트릭을합니다. 그것은 예쁜 기능 이름을 제공합니다 (그림 :)). 이것이 내가 필요한 것입니다.

즉, 그것은 다음을 제공합니다.

virtual bool mutex::do_unlock()

그러나 나는 그것이 다른 컴파일러에서 작동한다고 생각하지 않습니다.

Ali의 솔루션에 약간의 변화가 있습니다. 코드가 여전히 매우 유사하기를 원한다면

typeid(bla).name(),

대신 이것을 씁니다

Typeid(bla).name() (자본 첫 번째 편지에서만 다름)

그러면 이것에 관심이있을 수 있습니다.

파일로 타입 .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());
}
*/

class Typeid {
 public:

  template <class T>
    Typeid(const T& t) : typ(typeid(t)) {}

  std::string name() { return demangle(typ.name()); }

 private:
  const std::type_info& typ;
};


#endif

type.cpp Ali의 솔루션과 동일하게 유지됩니다

보세요 __cxa_demangle 당신이 찾을 수있는 것 cxxabi.h.

// KeithB's solution is good, but has one serious flaw in that unless buf is static
// it'll get trashed from the stack before it is returned in res - and will point who-knows-where
// Here's that problem fixed, but the code is still non-re-entrant and not thread-safe.
// Anyone care to improve it?

#include <cxxabi.h>

// todo: javadoc this properly
const char* demangle(const char* name)
{
    static char buf[1024];
    size_t size = sizeof(buf);
    int status;
    // todo:
    char* res = abi::__cxa_demangle (name,
                                 buf,
                                 &size,
                                 &status);
    buf[sizeof(buf) - 1] = 0; // I'd hope __cxa_demangle does this when the name is huge, but just in case.
    return res;
  }

그만큼 허용 된 솔루션 1] 대부분은 잘 작동합니다. 나는 적어도 하나의 사례를 발견했다 (그리고 코너 케이스라고 부르지 않을 것입니다).

이 경우 맨 아래에 게시 된 다른 솔루션을 찾았습니다.

문제가있는 경우 (사용 type 1])에 정의 된대로 :

int i = 1;
cout << "Type of " << "i" << " is " << type(i) << endl;
int & ri = i;
cout << "Type of " << "ri" << " is " << type(ri) << endl;

생산합니다

Type of i is int
Type of ri is int

해결책 (사용 type_name<decltype(obj)>(), 아래 코드 참조) :

cout << "Type of " << "i" << " is " << type_name<decltype(i)>() << endl;
cout << "Type of " << "ri" << " is " << type_name<decltype(ri)>() << endl;

생산합니다

Type of i is int
Type of ri is int&

원하는대로 (적어도 나에 의해)

암호. 전문화 문제로 인해 별도로 편집 된 소스가 아닌 포함 된 헤더에 있어야합니다. 보다 템플릿 함수에 대한 정의되지 않은 참조 예를 들어.

#ifndef _MSC_VER
#   include <cxxabi.h>
#endif
#include <memory>
#include <string>
#include <cstdlib>

template <class T>
std::string
type_name()
{
    typedef typename std::remove_reference<T>::type TR;
    std::unique_ptr<char, void(*)(void*)> own
           (
#ifndef _MSC_VER
                abi::__cxa_demangle(typeid(TR).name(), nullptr,
                                           nullptr, nullptr),
#else
                nullptr,
#endif
                std::free
           );
    std::string r = own != nullptr ? own.get() : typeid(TR).name();
    if (std::is_const<TR>::value)
        r += " const";
    if (std::is_volatile<TR>::value)
        r += " volatile";
    if (std::is_lvalue_reference<T>::value)
        r += "&";
    else if (std::is_rvalue_reference<T>::value)
        r += "&&";
    return r;
}

나는 항상 type_info를 사용하고 싶었지만 () 멤버 함수의 결과는 비표준이 아니며 반드시 의미있는 결과로 변환 할 수있는 것을 반드시 반환 할 필요는 없습니다.
하나의 컴파일러를 고수하는 경우 원하는 작업을 수행하는 컴파일러 별 기능이있을 수 있습니다. 문서를 확인하십시오.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top