todas - ¿Forma programática para obtener el nombre de la variable en C?
punteros en c (9)
Estoy desarrollando una herramienta para volcar datos de variables. Necesito volcar el nombre de la variable, y también los valores.
Mi solución: almacene el nombre de la variable como una cadena e imprima el "nombre de la variable", seguido de su valor.
¿Hay alguna forma programática de conocer el nombre de la variable?
De hecho, tengo un código que puede hacer lo que quieras. Utiliza el preprocesador para escribir el nombre de la variable para que pueda imprimirlo. Vacia tanto el nombre como el valor de la variable (según el tipo) y el diseño de la memoria para esa variable. El siguiente programa muestra cómo se hace:
#include <stdio.h>
#include <stdlib.h>
static void dumpMem (unsigned char *p, unsigned int s) {
int i;
unsigned char c[0x10];
printf (">> ");
for (i = 0; i < 0x10; i++) printf (" +%x",i);
printf (" +");
for (i = 0; i < 0x10; i++) printf ("%x",i);
printf ("/n");
for (i = 0; i < ((s + 15) & 0xfff0); i++) {
if ((i % 0x10) == 0) {
if (i != 0) printf (" %*.*s/n", 0x10, 0x10, c);
printf (">> %04x ",i);
}
if (i < s) {
printf (" %02x", p[i]);
c[i & 0xf] = ((p[i] < 0x20) || (p[i] > 0x7e)) ? ''.'' : p[i];
} else {
printf (" ");
c[i & 0xf] = '' '';
}
}
printf (" %*.*s/n", 0x10, 0x10, c);
}
#define DUMPINT(x) do{printf("%s: %d/n",#x,x);dumpMem((char*)(&x),sizeof(int));}while(0)
#define DUMPSTR(x) do{printf("%s: %s/n",#x,x);dumpMem(x,strlen(x));}while(0)
#define DUMPMEM(x,s) do{printf("%s:/n",#x);dumpMem((char*)(&x),s);}while(0)
typedef struct {
char c;
int i;
char c2[6];
} tStruct;
int main (void) {
int i = 42;
char *s = "Hello there, my name is Pax!";
tStruct z;
z.c = ''a''; z.i = 42; strcpy (z.c2,"Hello");
DUMPINT (i);
DUMPSTR (s);
DUMPMEM (z,sizeof(z));
return 0;
}
Esto produce:
i: 42
>> +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +a +b +c +d +e +f +0123456789abcdef
>> 0000 2a 00 00 00 *...
s: Hello there, my name is Pax!
>> +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +a +b +c +d +e +f +0123456789abcdef
>> 0000 48 65 6c 6c 6f 20 74 68 65 72 65 2c 20 6d 79 20 Hello there, my
>> 0010 6e 61 6d 65 20 69 73 20 50 61 78 21 name is Pax!
z:
>> +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +a +b +c +d +e +f +0123456789abcdef
>> 0000 61 b6 16 61 2a 00 00 00 48 65 6c 6c 6f 00 0d 61 a..a*...Hello..a
Y, si se está preguntando sobre la sensatez de do {...} while (0)
en las macros, eso es para permitir que se coloque en cualquier lugar del código sin tener que preocuparse de si tiene suficientes llaves que lo rodean.
En C, los nombres de las variables existen durante el paso de compilación (y el paso del enlace, si la variable es global), pero no están disponibles en el tiempo de ejecución. Debe elegir una solución que involucre una cadena literal que indique el nombre de la variable.
Forma más corta:
#define GET_VARIABLE_NAME(Variable) (#Variable)
prueba:
#include <string>
class MyClass {};
int main(int argc, char* argv[]) {
int foo = 0;
std::string var_name1 = GET_VARIABLE_NAME(foo);
char* var_name2 = GET_VARIABLE_NAME(foo);
char* var_name3 = GET_VARIABLE_NAME(MyClass);
return 0;
}
La gente a menudo quiere que los programas se autoencadenen (o "reflejen" en la jerga actual). Pero la mayoría de los lenguajes de programación ofrecen poca (por ejemplo, Java) o ninguna (C) capacidad para reflejar todos los detalles de un programa (nombres de variables, nombres de funciones, tipos, estructuras de expresiones, etc.).
Hay una forma de hacerlo para todos los idiomas: salga del idioma y use una herramienta diseñada para extraer esa información del idioma. Una clase de herramienta que puede hacer esto se llama sistema de transformación de programa.
Vea esta respuesta SO para una discusión sobre cómo "obtener nombres de variables" e imprimir valores usando un sistema de transformación de programas: Rastrea cambios en variables automáticamente
No hay una buena manera de hacerlo desde el interior de su programa, me temo (aparte de la respuesta de Anacrolix). Creo que la solución correcta para su problema es un script de depuración. En la mayoría de los depuradores, incluso puede conectarlo para ejecutar cada vez que el depurador interrumpe la ejecución del programa (punto de interrupción, toca ^C
, etc.) y obtener una instantánea del estado de su programa cada vez que interactúa con él.
Podrías probar algo como esto:
#define DUMP(varname) fprintf(stderr, "%s = %x", #varname, varname);
Solía usar este encabezado que escribí, cuando era nuevo en C, podría contener algunas ideas útiles. Por ejemplo, esto le permitiría imprimir un valor de C y proporcionar el especificador de formato en uno (así como también información adicional):
#define TRACE(fmt, var) /
(error_at_line(0, 0, __FILE__, __LINE__, "%s : " fmt, #var, var))
Si está usando C ++, puede usar el tipo del valor pasado y enviarlo de manera apropiada. Puedo proporcionar un ejemplo mucho más lucrativo de cómo "imprimir bastante" valores variables si este es el caso.
Prueba esto.
#define MACRO_VARIABLE_TO_STRING(Variable) ((void) Variable,#Variable)
Code (void) La variable es una conversión vacía que no es operativa, luego está el operador de coma y macro-string. Por lo tanto, el resultado neto es const char * que contiene el nombre de la variable con la verificación del compilador. La variable realmente existe.
Ahora tiene el nombre de su variable y puede usar printf () para imprimir su valor.
Si necesita hacer esto para variables arbitrarias, entonces probablemente necesite usar una API de depurador que el compilador o plataforma proporciona (como DbgHelp en Windows).
En algunos sistemas integrados en los que trabajé, hemos necesitado poder mostrar en el comando los valores de ciertas variables importantes que se conocen con anterioridad, y para hacer eso, todo lo que necesitamos es una simple tabla Nombre / puntero:
typedef
struct vartab {
char const* name;
int * var;
} vartab;
vartab varTable[] = {
{ "foo", &foo },
{ "bar", &bar }
};
Luego, acabo de utilizar una pequeña rutina que busca en la tabla el nombre de la variable en cuestión y vuelca el nombre y los datos apuntados por el puntero. Si necesita volcar datos que no sean simples, puede ampliar la estructura para que también contenga un formateador de estilo printf y cambie el puntero para que sea void*
y pase esa basura a snprintf()
o algo para formatear los datos.
Algunas veces también usaré una macro que ayude a construir la tabla (posiblemente también declare la variable). Pero para ser sincero, creo que eso realmente hace que sea más complejo de entender (especialmente para alguien nuevo que se une al proyecto, a menudo tienen un pequeño momento "WTF") y realmente no simplifica mucho las cosas.
Si su ejecutable está compilado con información de depuración, es posible que pueda obtener esta información. Si no, probablemente no tengas suerte. ¿Entonces estás construyendo un depurador? ¿Por qué? Los depuradores existentes para c son muy maduros. ¿Por qué no usar herramientas existentes en lugar de reinventar la rueda?