Существует ли эквивалент C для Perl-модуля Carp?
В некоторых проектах, которые я делал на C, мне нравилось использовать следующие макросы, которые работают подобно подпрограммам Perl warn и die:
#include <stdio.h>
#include <stdlib.h>
#define warn(...) \
fprintf(stderr, __VA_ARGS__); \
fprintf(stderr, " at %s line %d\n", __FILE__, __LINE__)
#define die(...) \
warn(__VA_ARGS__); \
exit(0xFF)
Существует ли что-либо, например, карп, хрипотца, треск и перфом в Perl? Я хотел бы что-то сообщить об ошибках с точки зрения пользователей.
Если нет, я знаю, что в glibc есть функции backtrace() и backtrace_symbols(), которые вместе с опцией -rdynamic gcc могут предоставить мне обратную трассировку имен функций и кодовых адресов. Но я хочу что-то немного лучше; с доступом к именам файлов, строк и функций в стеке вызовов, как в подпрограмме вызывающего Perl. с этим я смогу написать свой собственный libcarp для использования в моих программах на c.
РЕДАКТИРОВАТЬ: 2009-10-19
Я имею в виду создание чего-то, что использует gdb, когда доступно по базовому имени (argv[0]), а затем обрабатывает трассировку стека для создания различных типов сообщений, которые я хочу. Он должен быть в состоянии определить, находится ли я в отлаживаемом исполняемом файле или в системе без gdb, и в этом случае carp и cluck станут предупреждениями, а взломы и признания - умрут.
Я никогда не использовал GDB, как это раньше (я только запускаю его с моей программой в начале, а не тогда, когда она уже работает). Но я нашел несколько функций в glib (g_on_error_stack_trace и stack_trace), которые выглядят очень близко к тому, что я хочу сделать: он разветвляет процесс gdb с аргументами basename(argv[0]) и идентификатором процесса, а затем записывает в его stdin (который был перенаправлен на канал) команда "backtrace", а затем "выход". Затем он читает из своего результата и анализирует его так, как ему нравится. Это почти то, что мне нужно сделать.
4 ответа
Но я хочу что-то немного лучше с доступом к именам файлов, строк и функций в стеке вызовов, как подпрограмма вызывающего Perl.
Проблема в том, что для этого требуется помощь программиста, чтобы решить, где появляется граница между кодом вашей библиотеки и подпрограммой "вызывающий". Perl использует некоторую магию (или эвристику), чтобы сделать это; может быть, вы могли бы сделать то же самое с функциями возврата. Но это не тривиально, в общем.
Ну, я никогда не пытался показать стек вызовов, но для своих программ я делал следующее.
Сначала я определяю функцию, которая выполняет фактическую регистрацию. Это всего лишь пример; обратите внимание, что эта функция крайне небезопасна (кто-нибудь переполняет буфер?)
void strLog(char *file, char *function, int line, char *fmt, ...)
{
char buf[1024];
va_list args;
va_start(args, fmt);
vsprintf(buf, fmt, args);
va_end(args);
fprintf(stderr, "%s:%s:%d:%s\n", file, function, line, buf);
}
Однако это не очень практично. Практично использовать макрос для вызова этой функции.
#define die( ... ) \
strLog( __FILE__, __PRETTY_FUNCTION__, \
__LINE__, __VA_ARGS__ )
Тогда вы можете позвонить так же, как printf()
,
if (answer == 42) die("Oh, %d of course.", answer);
и вы получите что-то вроде этого:
main.c:10:somefunc: Oh, 42 of course.
Ну, нет следа, но что-то есть что-то.
Похоже, что не существует ничего подобного модулю Carp для использования в программах на C, поэтому я написал небольшую библиотеку для этого на github.
Библиотека имеет следующие экспорты, определенные для использования:
warn, die
carp, croak
cluck, confess
и я добавил электронные варианты предыдущих для добавления строк errno к предупреждению, так как я думал, что это будет полезно:
ewarn, edie
ecarp, ecroak
ecluck, econfess
Например, если вы пишете библиотеку и хотите придраться к проблеме, просто используйте
carp("%d is not a Fibonacci number!", 54);
И он покажет файл и номер строки первой функции, вызывающей вашу библиотеку.
Модуль Carl в Perl использует другой пакет вместо файла для поиска подозрительной подпрограммы. Он также использует массив @ISA или рекурсивно @CARP_NOT, чтобы определить, какая подпрограмма находится вне доверенной группы пакетов. Я намерен добавить что-то похожее на это. Если вершина трассировки стека находится в пределах доверенной области действия, то карп возвращается к значению (которое показывает полную трассировку стека проблемы), как это сделает эта библиотека.
Я написал подпрограмму обратного отслеживания для моих встроенных приложений C (gcc). Он использует информацию -gstabs, если она доступна, для поиска имен функций. Одно предостережение в том, что файл elf должен быть где-то, где программа может его найти, чтобы посмотреть в сегменте stabs. В моих встроенных приложениях эльфийский файл находится во флэш-памяти, и у меня есть указатель на него. В вашем случае вам придется написать код, чтобы прочитать его с диска.
Я почти уверен, что файл и номер строки также находятся в сегменте колов.
Похоже ли это на то, что может вам помочь?