Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a C equivalent for Perl's Carp module?

In some projects I've done in C, I've liked using the following macros which work similar to Perl's warn and die subroutines:

#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)

Does anything exist like Perl's carp, croak, cluck, and confess subroutines from Carp? I'd like to have something to report errors from the users perspective.

If not, I know there are backtrace() and backtrace_symbols() functions in glibc that along with the -rdynamic gcc option can supply me with a backtrace of function names and code addresses. But i want something a little better; with access to file, line, and function names in the call stack like Perl's caller subroutine. with that I'd be able to write my own libcarp for use in my c programs.

EDIT: 2009-10-19

I'm thinking of creating something that uses gdb when available on basename(argv[0]), then processes the stack trace to produce the different types of messages I want. It should be able to determine if im not in a debuggable executable, or a system without gdb, in which case, carp and cluck will become warns and craok and confess will become dies.

Ive never used gdb like this before (Ive only run it with my program at the beginning, not while its already running). But I found a few functions in glib (g_on_error_stack_trace and stack_trace) that looks very close to what i want to do: It forks a gdb process with the arguments basename(argv[0]) and the process id, then writes to its stdin (which has been redirected to a pipe) the command "backtrace" followed by a "quit". It then reads from its result and parses it the way it likes. This is almost exactly what i need to do.

like image 250
Jake Avatar asked Oct 19 '09 02:10

Jake


1 Answers

Well, I never tried to show the call stack, but for my programs I used to do the following.

First, I define a function that do the actual logging. This is just an example; please note that this function is highly insecure (buffer overrun anyone?)

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);
}

However, this is not very practical. What is practical is to use a macro to call this function.

#define die( ... ) \
        strLog( __FILE__, __PRETTY_FUNCTION__, \
        __LINE__, __VA_ARGS__ )

Then you can call just like printf().

if (answer == 42) die("Oh, %d of course.", answer);

and you would get something like this:

main.c:10:somefunc: Oh, 42 of course.

Well, no backtrace but something's something.

like image 196
Leonardo Herrera Avatar answered Sep 20 '22 19:09

Leonardo Herrera