Как найти имя текущей функции во время выполнения?

StackOverflow https://stackoverflow.com/questions/679021

  •  21-08-2019
  •  | 
  •  

Вопрос

После многих лет использования большого уродливого макроса MFC ASSERT я наконец решил отказаться от него и создать совершенный макрос ASSERT.

Меня устраивает получение номера файла и строки и даже выражения, которое не удалось.Я могу отобразить окно сообщения с ними и кнопки «Прервать/Повторить/Отменить».

И когда я нажимаю «Повторить», отладчик VS переходит к строке, содержащей вызов ASSERT (в отличие от дизассемблирования где-то, как некоторые другие функции ASSERT).Так что все вполне работает.

Но что было бы действительно здорово, так это отобразить имя функции, которая не удалась.

Тогда я смогу решить, следует ли его отлаживать, не пытаясь угадать, в какой функции он находится, по имени файла.

напримересли у меня есть следующая функция:

int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
   ASSERT(lpCreateStruct->cx > 0);
   ...
}

Затем, когда сработает ASSERT, в окне сообщения появится что-то вроде:

Function = CMainFrame::OnCreate

Итак, каков самый простой способ узнать текущее имя функции во время выполнения?

Он не должен использовать MFC или платформу .NET, хотя я использую и то, и другое.
Он должен быть максимально портативным.

Это было полезно?

Решение

Ваш макрос может содержать __FUNCTION__ макрос.Не ошибитесь, имя функции будет вставлен в расширенный код в время компиляции, но это будет правильное имя функции для каждого вызова вашего макроса.Так что "похоже" это происходит во время выполнения;)

например

#define THROW_IF(val) if (val) throw "error in " __FUNCTION__

int foo()
{
    int a = 0;
    THROW_IF(a > 0); // will throw "error in foo()"
}

Другие советы

Макрос препроцессора C++ __FUNCTION__ дает имя функции.

Обратите внимание, что если вы используете это, это не Действительно получение имени файла, номера строки или имени функции во время выполнения.Макросы расширяются препроцессором и компилируются.

А __FUNCTION__ макрос, типа __LINE__, и __FILE__, является частью языкового стандарта и является переносимым.

Пример программы:

#include <iostream>
#using namespace std;

void function1()
{
        cout << "my function name is: " << __FUNCTION__ << "\n";
}
int main()
{
        cout << "my function name is: " << __FUNCTION__ << "\n";
        function1();
        return 0;
}

выход:

my function name is: main
my function name is: function1

Стандартного решения не существует.Однако, BOOST_CURRENT_FUNCTION портативен для всех практических целей.Заголовок не зависит ни от одного из других заголовков Boost, поэтому его можно использовать автономно, если накладные расходы всей библиотеки неприемлемы.

В GCC вы можете использовать __PRETTY_FUNCTION__ макрос.
У Microsoft также есть аналог __func__ макрос, хотя у меня его нет, чтобы попробовать.

напримериспользовать __PRETTY_FUNCTION__ поместив что-то подобное в начало ваших функций, вы получите полную трассировку

void foo(char* bar){
  cout << __PRETTY_FUNCTION__ << std::endl
}

который выведет

void foo(char* bar)

У вас также есть __FILE__ и __LINE__ макросы, доступные во всех стандартных компиляторах c/c++, если вы хотите вывести еще больше информации.

На практике у меня есть специальный класс отладки, который я использую вместо cout.Определив соответствующие переменные среды, я могу получить полную трассировку программы.Вы могли бы сделать что-то подобное.Эти макросы невероятно удобны, и очень здорово иметь возможность включать такую ​​выборочную отладку в полевых условиях.

РЕДАКТИРОВАТЬ:видимо __func__ является частью стандарта?не знал этого.К сожалению, он дает только имя функции, а не параметры.мне нравятся gcc __PRETTY_FUNC__ но он не переносится на другие компиляторы.

GCC также поддерживает __FUNCTION__.

Вы можете использовать __FUNCTION__ макрос который во время компиляции будет расширен до имени функции.

Вот пример того, как использовать его в макросе утверждения.

#define ASSERT(cond) \
    do { if (!(cond)) \
    MessageBoxFunction("Failed: %s in Function %s", #cond, __FUNCTION__);\
    } while(0)

void MessageBoxFunction(const char* const msg,  ...)
{
    char szAssertMsg[2048];

    // format args
    va_list vargs;
    va_start(vargs, msg);
    vsprintf(szAssertMsg, msg, vargs);
    va_end(vargs);

    ::MessageBoxA(NULL, szAssertMsg, "Failed Assertion", MB_ICONERROR | MB_OK);
}

вы можете легко использовать функция.он вернет вам текущее имя функции во время выполнения, которое вызвало исключение.

Применение:

cout << __func__ << ": " << e.what();
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top