2016-11-25 17 views
11

У меня есть метод класса функции, ValueHolder :: printValueполучить C++ функции искореженного имя во время компиляции (или исполнение)

class ValueHolder { 

public: 
    void printValue(); 
} ; 

Как определить свое искаженное имя во время компиляции (или выполнения).

Например, я хотел бы сделать это:

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

Эта функция может возвращать строку как:

"_ZN11ValueHolder10printValueEv" 

Согласно @Marco А. Предпосылкой является современный компилятор. Один, который поддерживает typeid, и с включенными флагами, чтобы включить эту функцию.

Я также принимаю ответ, который может работать в практичности для Gcc & Clang и заглушки для MSVC.

ответ

-2

Хорошо, что вы можете сделать, это скомпилировать вашу C++-программу с помощью g ++ и получить файл .o. Запустите команду «nm» в файле .o, полученном таким образом, чтобы получить искаженные имена! Этот метод является жизнеспособным в системах Linux.

8

Там нет никакого стандартного способа сделать это, в соответствии с [lib.type.info]

Класс type_info описывает тип информации, полученной от реализации. Объекты этого класса эффективно сохраняют указатель на имя для типа и закодированное значение, подходящее для сравнения двух типов для равенства или порядка сортировки. Имена, правило кодирования и последовательность сортировки для типов не определены и могут различаться между программами.

и вашей реализации компилятора вы можете использовать typeid(type/expression).name(), но нигде не указано, или в исполнение, что это имя будет оформлен (это от реализации). Это также зависит от используемых флагов компиляции (спасибо malat).

Пример:

class ValueHolder { 

public: 
    void printValue(); 
}; 


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

gcc7.0

M11ValueHolderFvvE

clang4.0

M11ValueHolderFvvE

MSVC14

недействительным (__cdecl ValueHolder :: *) (ничтожной) __ptr64

+0

Просьба также уточнить, что это зависит не только от компилятора + версии, но и флаги компиляции (например, станд = C++ 11 и станд :: строки, и/или такие вещи, как '-DGLIBCXX_DEBUG') – malat

+0

@ malat Спасибо, я добавлю эту часть к ответу. –

+0

Это отличный ответ. Я собираюсь изменить вопрос чуть-чуть, чтобы отразить использование современного компилятора. – iamacomputer

3

Я добавлю ответ, но я не буду отмечать его правильно. Это не полно. Слишком большой, чтобы добавить в качестве комментария. Это то, что я могу сделать, но я ищу лучший способ. И, да, очень липкий-хриплый. Но я считаю, что есть какой-то 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

 Смежные вопросы

  • Нет связанных вопросов^_^