Perl的Carp模块是否有C等价物?

时间:2009-10-19 02:26:51

标签: c perl die backtrace 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的鲤鱼,呱呱,咯咯和来自Carp的忏悔子程序是否存在?我希望从用户角度报告错误。

如果没有,我知道glibc中有backtrace()和backtrace_symbols()函数,它们与-rdynamic gcc选项一起可以为我提供函数名和代码地址的回溯。但我想要一些更好的东西;可以访问调用堆栈中的文件,行和函数名称,如Perl的调用者子例程。因此,我可以编写自己的libcarp用于我的c程序。

编辑:2009-10-19

我正在考虑在basename(argv [0])上创建使用gdb的东西,然后处理堆栈跟踪以生成我想要的不同类型的消息。它应该能够确定我是不是在可调试的可执行文件中,还是没有gdb的系统,在这种情况下,carp和cluck会变成警告,并且忏悔并且忏悔将会死亡。

我之前从未使用过这样的gdb(我只在开始时使用我的程序运行它,而不是在它已经运行时)。但我发现glib中的一些函数(g_on_error_stack_trace和stack_trace)看起来非常接近我想做的事情:它使用参数basename(argv [0])和进程id分配gdb进程,然后写入其stdin(已被重定向到管道)命令“backtrace”后跟“退出”。然后它从结果中读取并按照它喜欢的方式解析它。这几乎就是我需要做的事情。

4 个答案:

答案 0 :(得分:1)

好吧,我从来没有尝试过显示调用堆栈,但对于我的程序,我曾经做过以下操作。

首先,我定义了一个执行实际日志记录的函数。这是只是一个例子;请注意,此功能是非常不安全的(缓冲区溢出任何人?)

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.

嗯,没有回溯,但有些东西。

答案 1 :(得分:1)

  

但是我希望通过访问调用堆栈中的文件,行和函数名称来更好一点,比如Perl的调用者子例程。

问题在于,这需要程序员帮助确定库代码和“调用者”子例程之间出现边界的位置。 Perl使用一些魔法(又名启发式)来做到这一点;也许你可以用回溯函数做同样的事情。但总的来说,这并非微不足道。

答案 2 :(得分:1)

似乎没有什么比Cp程序中使用的Carp模块更像,所以我在github编写了一个小型库。

库定义了以下导出使用:

warn, die
carp, croak
cluck, confess

我添加了以前的电子变种,用于在警告中添加errno字符串,因为我觉得它很有用:

ewarn, edie
ecarp, ecroak
ecluck, econfess

例如,如果您正在编写库并希望解决问题,请使用

carp("%d is not a Fibonacci number!", 54);

它将显示调用库的第一个函数的文件和行号。

Perl的Carp模块使用不同的包而不是文件来查找可疑的子例程。它还递归地使用@ISA数组或@CARP_NOT来确定哪个子例程在受信任的包组之外。我打算添加类似的东西。如果堆栈跟踪的顶部在可信范围内,那么鲤鱼会恢复到一个cluck(显示问题的完整堆栈跟踪),就像这个库一样。

答案 3 :(得分:0)

我为嵌入式C(gcc)应用编写了回溯例程。它使用-gstabs信息(如果可用)来查找函数名称。需要注意的是,elf文件必须位于程序可以找到的位置,以便查看stabs段。在我的嵌入式应用程序中,elf文件位于flash中,我有一个指向它的指针。在你的情况下,你必须写一些代码来从磁盘上读取它。

我很确定文件和行号也在stabs段中。

这听起来像是可以帮到你的东西吗?