2011-03-29 7 views
16

En C++, teniendo¿Cómo puedo imprimir valores en C sin especificar sus tipos, como se hace con "cerr << (A) << endl" en C++?

#define DEBUG(A) cerr << (A) << endl; 

puedo enviar nada a ella, y puede imprimirlo. Sin embargo, en C, debo especificar su tipo con% d,% c o% s, etc. Pero no quiero escribir su tipo todo el tiempo, quiero usar fprintf como cerr. ¿Cómo puedo hacer eso?

Por ejemplo: en C

#define DEBUG(A) X // X is what I want to write 
... 
// in function, when I put 
DEBUG(5);   // I just want to print 5 
// or, with same statement, when I say 
DEBUG('a');  // output : a 
+0

¿Seguro que quieres utilizar 'endl'? Provoca un flujo de la corriente que realmente ralentizará el programa. –

+1

Como nota al margen, la práctica estándar al escribir cualquier forma de macro como función es poner paréntesis alrededor de toda la expresión. – Lundin

+5

@mattieu: sí, quiere usar 'endl': en depuración está bien para ralentizar el programa. Y: desea ver cada línea en la consola, mientras el programa la ejecuta. No ruborizarse significaría: no * ve * lo que acaba de imprimir, a veces. Eso dificulta la depuración. – towi

Respuesta

30

puede utilizar GNU C Language Extensions:

#define DEBUG(x)             \ 
    ({                \ 
    if (__builtin_types_compatible_p (typeof (x), int))   \ 
     fprintf(stderr,"%d\n",x);        \ 
    else if (__builtin_types_compatible_p (typeof (x), char)) \ 
     fprintf(stderr,"%c\n",x);        \ 
    else if (__builtin_types_compatible_p (typeof (x), char[])) \ 
     fprintf(stderr,"%s\n",x);        \ 
    else               \ 
     fprintf(stderr,"unknown type\n");      \ 

    }) 

Éstos están muy bien:

DEBUG("hello"); //prints hello 
DEBUG(11110); //prints 11110 

Pero para caracteres, que debe administrarse con lvalue, de lo contrario su tipo será "int":

char c='A'; 
DEBUG(c); // prints A 
DEBUG('A'); // prints 65 
+2

Querrá agregar 'fflush (stderr);' al final de la macro para obtener el mismo efecto que 'endl' –

+2

stderr no se almacena en el búfer en realidad, por lo que no es necesario fflush. Y stdout es buffer de línea, por lo que \ n se encargaría de eso en ese caso. –

+0

En la versión final, ¿qué tal 'write'ing' sizeof (x) 'bytes de' & x' para dar al menos una buena oportunidad de recuperar datos útiles? –

14

No puede utilizar fprintf() en la forma que desee. Bienvenido a C.

operadores de flujo C++ I/O son typesafe y utilizar la sobrecarga de operadores para lograr su magia. Eso no está disponible en C, por lo que debe mantener el enfoque de cadena de formato inseguro.

10

En principio, no se puede, como C no tienen un mecanismo de sobrecarga.

Puede, sin embargo, definir un número de macros como:

#define DEBUG_INT(x) fprintf(stderr, "%d\n", (x)) 
#define DEBUG_CHAR(x) fprintf(stderr, "%c\n", (x)) 
8

No hay manera de deshacerse de las especificaciones de conversión, pero si usted tiene un compilador C99, puede utilizar __VA_ARGS__ y hacerlo un poco más fácil, como, por ejemplo, en

#include <stdio.h> 

#define DEBUG(fmt, ...) fprintf(stderr, (fmt), __VA_ARGS__) 

int main(void) { 
    int foo = 42; 
    char *t = "foobar"; 
    DEBUG("%s:%d\n", t, foo); 
    return 0; 
} 
+3

O aún más fácil: llame al bloody fprintf() directamente desde el programa :) – Lundin

+0

@Konstantin: ¿tiene una referencia para esa palabra clave '_Generic'? – pmg

+0

lo siento, no es C99, es del nuevo borrador estándar. –

0

En C, no se puede determinar con fiabilidad el tipo de un objeto. Por lo tanto, tendrías que introducir algún mecanismo para admitir la programación genérica, p. adjuntando todos los objetos en una estructura que mantiene la información del tipo:

enum {type_int, type_double, type_string, /* ... */ } type_t; 
struct { 
     type_t type; 
     void *obj; 
} generic_type; 

Ahora, puede cambiar durante ((generic_type)my_object).type. Esto probablemente no es lo que estás buscando.



Sin embargo, hay un truco fácil de decir si un argumento macro es una cadena literal o alguna otra cosa. Con el carácter citando macro '#', puede activar un argumento macro en una cadena:

#define DEBUG(x) if (#x[0] == '"') printf("%s\n", x); else printf("%d\n", x) 

Ahora usted puede hacer lo siguiente:

DEBUG("foo bar"); // prints "foo bar" 
DEBUG(23);   // prints "23" 

En el lado negativo, esto no le fallará distinguir entre, por ejemplo int sy float s.Por otra parte, los punteros-a-char no se reconocen como cadenas:

char *foo = "bar"; 
DEBUG(foo);  // prints the value of foo, not the string pointed to by foo 

double salary; 
DEBUG(salary);  // prints (int)salary, not (double)salary 

En algunas máquinas, sizeof(double) != sizeof(int). Esto podría ayudar a distinguir aún más entre los diferentes tipos de argumentos de macro, pero ciertamente no es portátil.



En términos generales, usted no será capaz de resolver completamente este problema sin algún esfuerzo serio hacia el soporte de programación genérica al mismo tiempo mantener la portabilidad.

Mi consejo: simplemente acostúmbrate a formatear los especificadores.

0

lugar de utilizar el __VA_ARGS__, puede simplemente hacer lo siguiente:

#define DEBUG(x...) fprintf(stderr, x) 

A diferencia del CCG métodos incorporados, este método le permite mezclar y combinar - se puede imprimir "cadena = ", en lugar de solo un tipo a la vez. Tampoco se encontrará con el tamaño y la incompatibilidad de tipos de esta manera: es esencialmente lo mismo que fprintf, ¡excepto que puede excluirse en el momento de la compilación!

Cuestiones relacionadas