2009-10-19 10 views
7

En algunos proyectos que he hecho en C, me ha gustado usar las siguientes macros, que funcionan de manera similar a Perl de advertir y mueren subrutinas:¿Hay un equivalente en C para el módulo Perl's Carp?

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

hace nada existir como la carpa de Perl, croar, clica, y confesar subrutinas desde Carp? Me gustaría tener algo para informar los errores desde la perspectiva de los usuarios.

Si no, sé que hay funciones backtrace() y backtrace_symbols() en glibc que junto con la opción -dinámica gcc pueden proporcionarme una traza inversa de nombres de funciones y direcciones de código. Pero quiero algo un poco mejor; con acceso a nombres de archivo, línea y función en la pila de llamadas como la subrutina de llamada de Perl. con eso podría escribir mi propio libcarp para usar en mis programas c.

EDIT: 2009-10-19

Estoy pensando en la creación de algo que usa GDB cuando esté disponible el nombre base (argv [0]), a continuación, procesa el seguimiento de la pila para producir los diferentes tipos de mensajes que quiero . Debería poder determinar si no estoy en un ejecutable depurable, o en un sistema sin gdb, en cuyo caso, la carpa y el cloqueo se advertirán y se confundirán y confesarán.

Nunca he usado gdb de esta manera antes (solo lo he ejecutado con mi programa al principio, no cuando ya se estaba ejecutando). Pero encontré algunas funciones en glib (g_on_error_stack_trace y stack_trace) que se parece mucho a lo que quiero hacer: bifurca un proceso de gdb con los argumentos nombre base (argv [0]) y la identificación del proceso, luego escribe en su stdin (que ha sido redirigido a una tubería) el comando "backtrace" seguido de un "quit". Luego lee de su resultado y lo analiza de la manera que le gusta. Esto es casi exactamente lo que necesito hacer.

+11

Para aquellos que no están familiarizados con Perl, la carpa y croak hacen lo que el ejemplo advierte y las macros mueren, solo con el archivo y la línea de la persona que llama del submarino actual. cluck y confess hacen lo mismo, solo con un seguimiento de pila completo. (algunos detalles simplificados) – ysth

+4

Documentos en: http://perldoc.perl.org/Carp.html – Ether

+4

Para las macros de multi-declaraciones verdaderas, se recomienda encapsularlas en {...} mientras (0), para hacer utilizar como una declaración de trabajo como se esperaba. – unwind

Respuesta

1

Bueno, nunca intenté mostrar la pila de llamadas, pero para mis programas solía hacer lo siguiente.

Primero, defino una función que hace el registro real. Esto es solo un ejemplo; tenga en cuenta que esta función es muy insegura (desbordamiento de búfer a nadie?)

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

Sin embargo, esto no es muy práctico. Lo que es práctico es usar una macro para llamar a esta función.

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

A continuación, puede llamar al igual que printf().

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

y se podrían obtener algo como esto:

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

Bueno, no traza pero algo es algo.

+0

Parece que Jake ya ha llegado tan lejos. –

+2

Utilice vsnprintf() para evitar el desbordamiento del búfer. O use dos llamadas a fprintf(): una para la información de archivo/función/línea y la otra como vfprintf() para tratar el formato proporcionado por el usuario. El código de todos parece estar olvidando imprimir el nombre del programa - argv [0]; eso requiere cierta disciplina de instalación, sin embargo. –

+1

Si desea evitar el desbordamiento del búfer, la forma más fácil de hacerlo es llamar a 'vasprintf' en lugar de 'vsnprintf'. –

1

Pero quiero algo un poco mejor con el acceso a nombres de archivos, líneas y funciones en la pila de llamadas como la subrutina de llamadas de Perl.

El problema es que esto requiere la ayuda del programador para decidir dónde aparece el límite entre el código de su biblioteca y la subrutina 'llamante'. Perl usa algo de magia (también conocida como heurística) para hacer eso; tal vez podrías hacer lo mismo con las funciones de rastreo. Pero no es trivial, en general.

+1

La magia a la que se hace referencia aquí es la función de llamada que se proporcionó fue una de las funciones integradas. No hay una función estándar en la definición del lenguaje C que proporcione una capacidad equivalente. –

+0

Quise decir "La magia a la que se hace referencia aquí es la función de llamada que se suministra como una de las funciones integradas de Perl. No hay una función estándar en la definición de lenguaje C que proporcione una capacidad equivalente". –

+1

@David: Sé a lo que te refieres, y es difícil explicar cuál sería el equivalente en C, entre otras cosas porque no hay un equivalente en los entornos C estándar. Y tengo entendido que el Perl 'caller' incorporado funciona a partir de la pila de Perl o datos relacionados con la función de llamada. –

0

Escribí la rutina backtrace para mis aplicaciones C (gcc) incrustadas. Utiliza la información -gstabs si está disponible para buscar nombres de funciones. Una advertencia es que el archivo elf debe estar en algún lugar donde el programa pueda encontrarlo, para poder buscar en el segmento de las estacas. En mis aplicaciones integradas, el archivo elf está en flash y tengo un puntero a él. En su caso, tendría que escribir un código para leerlo en el disco.

Estoy bastante seguro de que el archivo y el número de línea también están en el segmento de puñaladas.

¿Esto suena como algo que podría ayudarle?

1

Parece que no existe nada como el módulo Carp para usar en programas C, así que escribí una pequeña biblioteca para hacerlo en github.

La biblioteca tiene las siguientes exportaciones definidos para su uso:

warn, die 
carp, croak 
cluck, confess 

y he añadido correos variedades de las anteriores para añadir cadenas errno a la advertencia ya que pensé que sería útil:

ewarn, edie 
ecarp, ecroak 
ecluck, econfess 

Por ejemplo, si usted está escribiendo una biblioteca y quieren carpa sobre un problema, sólo tiene que utilizar

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

Y mostrará el número de archivo y línea de la primera función que llama a su biblioteca.

El módulo Perl's Carp usa un paquete diferente, en lugar de un archivo, para encontrar la supuesta subrutina. También utiliza la matriz @ISA o @ CARP_NOT recursivamente para determinar qué subrutina está fuera de un grupo confiable de paquetes. Tengo la intención de agregar algo similar a esto. Si la parte superior de la pila está dentro del ámbito de confianza, la carpa vuelve a un cluck (que muestra una pila completa del problema) del mismo modo que lo hará esta biblioteca.

+0

NB: A partir de 2012-09-06, el enlace de Github es 404. –

Cuestiones relacionadas