Как я нахожу название функции вызова?

46
задан Phil Hannent 24 July 2014 в 08:36
поделиться

4 ответа

Вот две опции:

  1. можно получить полный stacktrace (включая имя, модуль и смещение функции вызова) с последними версиями glibc с функции следа GNU . См. мой ответ здесь для деталей. Это - вероятно, самая легкая вещь.

  2. , Если это не точно, что Вы ищете, тогда Вы могли бы попробовать libunwind, но он собирается включить больше работы.

Имеют в виду, что это не что-то, что можно знать статически (как с PRETTY_FUNCTION); на самом деле необходимо обойти стек для выяснения то, что функция позвонила Вам. Таким образом, это не что-то, что это действительно стоит сделать в обычной отладке printfs. Если Вы хотите сделать более серьезную отладку или анализ, тем не менее, тогда, это могло бы быть полезно для Вас.

22
ответ дан Community 26 November 2019 в 20:21
поделиться

Вот решение, которое можно часто использовать. Это имеет преимущество требования никаких изменений в фактическом функциональном коде (, никакое добавление не звонит в функции прохода по стеку, изменение параметров для передачи на имена функций или соединение с дополнительными библиотеками. ). Для получения его работа просто необходимо использовать немного волшебства препроцессора:

Простой Пример

// orignal function name was 'FunctionName'
void FunctionNameReal(...)
{
  // Do Something
}

#undef FunctionName
#define FunctionName printf("Calling FunctionName from %s\n",__FUNCTION__);FunctionNameReal

необходимо переименовать функцию временно, но видеть примечание ниже для большего количества предложений. Это приведет к printf() оператор в каждой точке вызывания функции. Очевидно, необходимо сделать некоторые приготовления, если Вы называете функцию членства или должны получить возвращаемое значение ( Как передача вызов функции и __FUNCTION__ к пользовательской функции, которая возвращает тот же тип... ), но основная техника является тем же. Вы могли бы хотеть использовать __LINE__ и __FILE__ или некоторые другие макросы препроцессора, в зависимости от которых компилятора Вы имеете. (Этот пример специально для VC MS ++, но вероятно работает в других.)

кроме того, Вы могли бы хотеть поместить что-то вроде этого в свой заголовок, окруженный [1 110] защита для условного включения его, который может обработать переименование фактической функции для Вас также.

ОБНОВЛЕНИЕ [2012-06-21]

я заставил запрос разворачивать мой ответ. Как оказалось, мой выше примера немного упрощен. Вот некоторые полностью компилирующие примеры обработки этого, с помощью C++.

Полный Исходный Пример с возвращаемым значением

Используя class с [1 112] делает это довольно прямым. Эта первая техника работает на автономные функции с и без возвращаемых значений. operator() просто потребности отразить тот же возврат как рассматриваемая функция, и иметь соответствие аргументам.

можно скомпилировать это с [1 114] для версии несоздания отчетов и g++ -o test test.cpp -DREPORT для версии, которая отображает информацию о вызывающем абоненте.

#include <iostream>

int FunctionName(int one, int two)
{
  static int calls=0;
  return (++calls+one)*two;
}

#ifdef REPORT
  // class to capture the caller and print it.  
  class Reporter
  {
    public:
      Reporter(std::string Caller, std::string File, int Line)
        : caller_(Caller)
        , file_(File)
        , line_(Line)
      {}

      int operator()(int one, int two)
      {
        std::cout
          << "Reporter: FunctionName() is being called by "
          << caller_ << "() in " << file_ << ":" << line_ << std::endl;
        // can use the original name here, as it is still defined
        return FunctionName(one,two);
      }
    private:
      std::string   caller_;
      std::string   file_;
      int           line_;

  };

// remove the symbol for the function, then define a new version that instead
// creates a stack temporary instance of Reporter initialized with the caller
#  undef FunctionName
#  define FunctionName Reporter(__FUNCTION__,__FILE__,__LINE__)
#endif


void Caller1()
{
  int val = FunctionName(7,9);  // <-- works for captured return value
  std::cout << "Mystery Function got " << val << std::endl;
}

void Caller2()
{
  // Works for inline as well.
  std::cout << "Mystery Function got " << FunctionName(11,13) << std::endl;
}

int main(int argc, char** argv)
{
  Caller1();
  Caller2();
  return 0;
}

Демонстрационный Вывод (Сообщая)

Reporter: FunctionName() is being called by Caller1() in test.cpp:44
Mystery Function got 72
Reporter: FunctionName() is being called by Caller2() in test.cpp:51
Mystery Function got 169

В основном, где угодно это FunctionName происходит, он заменяет его [1 117], результирующий эффект которого является препроцессором, пишущий некоторое инстанцирование объекта с непосредственным вызовом к эти operator() функция. Можно просмотреть результат (в gcc) замен препроцессора с [1 119]. Caller2 () становится этим:

void Caller2()
{
  std::cout << "Mystery Function got " << Reporter(__FUNCTION__,"test.cpp",51)(11,13) << std::endl;
}

Вы видите, что __LINE__ и __FILE__ были заменены. (Я не уверен, почему __FUNCTION__ все еще шоу в выводе честно говоря, но скомпилированная версия сообщает о правильной функции, таким образом, это, вероятно, имеет некоторое отношение к многопроходной предварительной обработке или gcc ошибке.)

Полный Исходный Пример с Функцией членства

Класса Это немного более сложно, но очень похоже на предыдущий пример. Вместо того, чтобы просто заменить вызов к функции, мы также заменяем класс.

Как вышеупомянутый пример, можно скомпилировать это с [1 123] для версии несоздания отчетов и g++ -o test test.cpp -DREPORT для версии, которая отображает информацию о вызывающем абоненте.

#include <iostream>

class ClassName
{
  public:
    explicit ClassName(int Member)
      : member_(Member)
      {}

    int FunctionName(int one, int two)
    {
      return (++member_+one)*two;
    }

  private:
    int member_;
};

#ifdef REPORT
  // class to capture the caller and print it.  
  class ClassNameDecorator
  {
    public:
      ClassNameDecorator( int Member)
        : className_(Member)
      {}

      ClassNameDecorator& FunctionName(std::string Caller, std::string File, int Line)
      {
        std::cout
          << "Reporter: ClassName::FunctionName() is being called by "
          << Caller << "() in " << File << ":" << Line << std::endl;
        return *this;
      }
      int operator()(int one, int two)
      {
        return className_.FunctionName(one,two);
      }
    private:
      ClassName className_;
  };


// remove the symbol for the function, then define a new version that instead
// creates a stack temporary instance of ClassNameDecorator.
// FunctionName is then replaced with a version that takes the caller information
// and uses Method Chaining to allow operator() to be invoked with the original
// parameters.
#  undef ClassName
#  define ClassName ClassNameDecorator
#  undef FunctionName
#  define FunctionName FunctionName(__FUNCTION__,__FILE__,__LINE__)
#endif


void Caller1()
{
  ClassName foo(21);
  int val = foo.FunctionName(7,9);  // <-- works for captured return value
  std::cout << "Mystery Function got " << val << std::endl;
}

void Caller2()
{
  ClassName foo(42);
  // Works for inline as well.
  std::cout << "Mystery Function got " << foo.FunctionName(11,13) << std::endl;
}

int main(int argc, char** argv)
{
  Caller1();
  Caller2();
  return 0;
}

Вот демонстрационный вывод:

Reporter: ClassName::FunctionName() is being called by Caller1() in test.cpp:56
Mystery Function got 261
Reporter: ClassName::FunctionName() is being called by Caller2() in test.cpp:64
Mystery Function got 702

звездные часы этой версии являются классом, который украшает исходный класс и заменяющую функцию, которая возвращает ссылку на экземпляр класса, позволяя operator() делать фактический вызов функции.

Hope, которая помогает кому-то!

47
ответ дан Aaron 26 November 2019 в 20:21
поделиться

В приближении елей, просто grep кодовая база для имен функций. Тогда прибывает Doxygen, и затем динамический вход (оба обсужденные другими).

1
ответ дан 26 November 2019 в 20:21
поделиться

Вы, вероятно, хотите названия всех функций, которые потенциально могли назвать их. Это - в основном ряд краев в графе вызовов. doxygen может генерировать граф вызовов, и затем это - просто вопрос рассмотрения входящих краев Вашего узла функций.

1
ответ дан albert 26 November 2019 в 20:21
поделиться
Другие вопросы по тегам:

Похожие вопросы: