Потребность C/C++ умный способ отследить вызовы функции

Я ищу умный способ отследить вызовы функции и возвраты. Я знаю, что могу использовать отладчик, но я хотел бы способ просто иметь его, распечатывают что-то к терминалу при вызывании функции по сравнению с необходимостью ступить через код.
Я думаю, что смог использовать препроцессор, но я не уверен, каков был бы лучший способ пойти об этом.
Или есть ли способ использовать gdb для распечатывания информации, которая была бы полезна, не имея необходимость ступить через код.

6
задан Brian Tompsett - 汤莱恩 26 February 2016 в 09:35
поделиться

7 ответов

Большинство компиляторов позволяют внедрить функцию инструментации до и после вызова функции.

в msvc это _penter и _pexit
. хорошая статья http://www.drdobbs.com/184403601

в gcc вы можете использовать -finstrument-functions
http://gcc.gnu.org/onlinedocs/gcc-4.4.4/gcc/Code-Gen-Options.html

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

14
ответ дан 8 December 2019 в 02:52
поделиться

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

class ScopeLogger {
public:
   ScopeLogger( std::string const & msg ) : msg(msg)
   {   std::cout << "Enter: " << msg << std::endl; }
   ~ScopeLogger()
   {   std::cout << "Exit:  " << msg << std::endl; }
   std::string msg;
};
#if DEBUG
#define FUNCTION(x) ScopeLogger l_##x##_scope(x);
#endif

void foo( int value ) {
   FUNCTION( __FUNCTION__ );
   if ( value > 10 ) throw std::exception;
   std::cout << "." << std::endl;
}

int main() {
   foo(0);    // Enter: foo\n.\nExit:  foo
   foo(100);  // Enter: foo\nExit:  foo
}

Если код однопоточный, вы можете даже захотеть добавить статическую переменную с некоторым уровнем отступа к ScopedLogger, не добавляя слишком много к и без того тяжелому влиянию на производительность:

class ScopeLogger {
public:
   ScopeLogger( std::string const & msg ) : msg(msg)
   {   std::cout << std::string(indent++,' ') << "Enter: " << msg << std::endl; }
   ~ScopeLogger()
   {   std::cout << std::string(--indent,' ') << "Exit:  " << msg << std::endl; }
   std::string msg;
   static int indent;
};
int ScopeLogger::indent = 0;
5
ответ дан 8 December 2019 в 02:52
поделиться
#define BEGIN_FUNC(X) printf("Function %s Entered",X)
#define END_FUNC(X)  printf("Function %s End",X)

foo()
{
BEGIN_FUNC(__func__);

//Your code here


END_FUNC(__func__);


}

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

3
ответ дан 8 December 2019 в 02:52
поделиться

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

3
ответ дан 8 December 2019 в 02:52
поделиться

Или есть ли способ использовать gdb для вывода полезной информации, при этом не перебирая код

Да. Установите точку останова только в тех функциях, которые вас действительно интересуют. Используйте "continue", пока не дойдете до этих функций или пока программа не завершится аварийно. Затем используйте "backtrace" (или "bt"), чтобы получить трассировку стека.

2
ответ дан 8 December 2019 в 02:52
поделиться

Если вам нужно автоматизировать это, вы можете взглянуть на TARGET_ASM_FUNCTION_END_PROLOGUE и TARGET_ASM_FUNCTION_BEGIN_EPILOGUE. Это крючки компилятора, которые позволят вам указать части сборки, которые будут выдаваться вместе с обычным прологом/эпилогом функции - в вашем случае, вы бы использовали их для выдачи небольшой сборки для регистрации входа/выхода из рассматриваемой функции. Вы также можете посмотреть на FUNCTION_PROFILE и/или PROFILE_HOOK (например, на: http://gcc.gnu.org/onlinedocs/gccint/Function-Entry.html).

1
ответ дан 8 December 2019 в 02:52
поделиться

Существует макрос __ FUNCTION __ (Ссылка) , используемый для определения того, какой метод (в формате Class :: Method ) вы используете, но это больше ручной процесс.

Однако, когда мне недавно понадобилась та же самая «трассировочная» информация, я не смог найти автоматический метод.

0
ответ дан 8 December 2019 в 02:52
поделиться