在我用C语言完成的一些项目中,我喜欢使用下面的宏,它们的工作原理类似于Perl的warn和dey子例程:
#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)Carp中是否存在类似Perl的carp、croak、cluck和convene子例程?我想从用户的角度来报告一些错误。
如果没有,我知道glibc中有backtrace()和backtrace_symbols()函数,它们和-rdynamic的gcc选项可以为我提供函数名和代码地址的回溯。但是我想要一些更好的东西;能够访问调用堆栈中的文件名、行名和函数名,比如Perl的调用子例程。这样,我就可以编写自己的libcarp,以便在c程序中使用。
编辑: 2009-10-19
我正在考虑创建一些在basename(argv)上可用时使用gdb的东西,然后处理堆栈跟踪以生成我想要的不同类型的消息。它应该能够确定im是否不在一个可调试的可执行文件中,或者是一个没有gdb的系统,在这种情况下,carp和cluck将变成warns和craok,而认罪将变成死亡。
我以前从来没有使用过这样的gdb (我只是在一开始就用我的程序运行它,而不是在它已经运行的时候)。但我在glib (g_on_error_stack_trace和stack_trace)中发现了一些看起来非常接近我想要做的事情的函数:它使用参数basename(argv)和进程id派生一个gdb进程,然后将命令"backtrace“和"quit”写入其标准输入(已被重定向到管道)。然后,它从结果中读取并以它喜欢的方式进行解析。这几乎就是我需要做的。
发布于 2009-10-19 12:37:11
好吧,我从来没有尝试过展示调用堆栈,但是对于我的程序,我曾经做过以下事情。
首先,我定义了一个执行实际日志记录的函数。这只是一个示例;请注意这个函数是高度不安全的(有人缓冲区溢出吗?)
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.好吧,没有回溯,但有些东西。
发布于 2009-10-19 15:08:38
,但是我想要一些更好的东西,能够访问调用堆栈中的文件名、行名和函数名,比如Perl的调用子例程。
问题是,这需要程序员的帮助来决定您的库代码和“调用者”子例程之间的边界出现在哪里。Perl使用一些魔法(也称为启发式)来实现这一点;也许您可以使用回溯函数来做同样的事情。但总的来说,这并不是微不足道的。
发布于 2009-10-26 05:50:51
似乎没有什么比在C程序中使用的Carp模块更好的了,所以我在github上写了一个小库来做这件事。
该库定义了以下导出以供使用:
warn, die
carp, croak
cluck, confess我已经添加了之前的e变体,用于在警告中添加errno字符串,因为我认为这会很有用:
ewarn, edie
ecarp, ecroak
ecluck, econfess例如,如果您正在编写一个库,并且想要对一个问题吹毛求疵,那么只需使用
carp("%d is not a Fibonacci number!", 54);它将显示调用您的库的第一个函数的文件和行号。
Perl的Carp模块使用不同的包而不是文件来查找可疑的子例程。它还递归地使用@ISA数组或@CARP_NOT来确定哪个子例程在受信任的程序包组之外。我打算添加一些类似的东西。如果堆栈跟踪的顶部在受信任的作用域内,则carp恢复为cluck (显示问题的完整堆栈跟踪),就像这个库所做的那样。
https://stackoverflow.com/questions/1586709
复制相似问题