¿Forma programática de obtener el nombre de la variable en C?

7 minutos de lectura

avatar de usuario
alfaneo

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 saber el nombre de la variable?

avatar de usuario
carpintero mate

Podrías intentar algo como esto:

#define DUMP(varname) fprintf(stderr, "%s = %x", #varname, varname);

Solía ​​usar este encabezado Escribí, cuando era nuevo en C, podría contener algunas ideas útiles. Por ejemplo, esto le permitiría imprimir un valor C y proporcionar el especificador de formato en uno (así como información adicional):

#define TRACE(fmt, var) \
        (error_at_line(0, 0, __FILE__, __LINE__, "%s : " fmt, #var, var))

Si usa C++, puede usar el tipo del valor pasado y generarlo de manera adecuada. Puedo proporcionar un ejemplo mucho más lucrativo de cómo “imprimir bastante” los valores de las variables si este es el caso.

  • Esa es una buena idea para hacer las cosas desde dentro del programa. Crea un montón de constantes de cadena, eso es seguro.

    –Carl Norum

    26 de octubre de 2009 a las 4:57

  • Probablemente sea mejor definirlo como DUMP(varname, format) y usando "%s = " format "\n" en el fprintflo que le permite trabajar en más tipos: DUMP(somestring, "%s") o DUMP(someint, "%d").

    – café

    26 de octubre de 2009 a las 5:14

  • Esta es la forma habitual de evitar la naturaleza no introspectiva de c. Como puede imaginar, tiene sus límites y trampas, pero es lo mejor que puede hacer sin construir su propio intérprete introspectivo.

    – dmckee — gatito ex-moderador

    26 de octubre de 2009 a las 10:29

  • En DUMP ¿Por qué estás reemplazando? #varname con %s? Simplemente use la concatenación de cadenas implícita: #define DUMP(Var) (fprintf(stderr, #Var "= %p", Var))

    – JackKelly

    3 de septiembre de 2010 a las 0:33


  • @Jack Kelly: No puede estar seguro de qué se dará exactamente en var, de cualquier manera, debe imprimirse como una cadena. Esto no funcionaría bien si var era 22 % 7

    – Matt Carpintero

    3 de septiembre de 2010 a las 2:49

En C, los nombres de las variables existen durante el paso de compilación (y el paso de enlace, si la variable es global), pero no están disponibles en tiempo de ejecución. Debe elegir una solución que involucre una cadena literal que indique el nombre de la variable.

Camino más corto:

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

  • Bonito y limpio.

    – Daniel

    11 de septiembre de 2020 a las 13:48

De hecho, tengo un código que puede hacer lo que quieras. Utiliza el preprocesador para encadenar el nombre de la variable para permitirle imprimirlo. Vuelca 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 da como resultado:

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 te estás preguntando acerca de la cordura de do {...} while (0) en las macros, eso es para permitir que se coloque en cualquier parte del código sin tener que preocuparse de si tiene suficientes llaves alrededor.

avatar de usuario
miguel rebabas

Si necesita hacer esto para variables arbitrarias, entonces probablemente necesitará usar una API de depuración que proporciona el compilador o la plataforma (como DbgHelp en Windows).

En algunos sistemas integrados en los que trabajé, necesitábamos poder mostrar en comando los valores de ciertas variables importantes que se conocen con anticipación, y para hacer eso, todo lo que necesitamos es una tabla simple de Nombre/puntero:

typedef 
struct vartab {
    char const* name;
    int * var;
} vartab;


vartab varTable[] = {
    { "foo", &foo },
    { "bar", &bar }
};

Luego simplemente usé una pequeña rutina que busca en la tabla el nombre de la variable en cuestión y descarga el nombre y los datos señalados por el puntero. Si necesita volcar datos que no sean enteros simples, puede extender la estructura para que también contenga un formateador de estilo printf y cambiar el puntero para que sea un void* y pasar esa basura a snprintf() o algo para formatear los datos.

A veces también uso una macro que ayuda a construir la tabla (posiblemente también declarando la variable). Pero para ser honesto, creo que eso realmente lo hace 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.

  • ¿Podría decirme un poco más sobre cómo usaría la macro que ayuda a construir la tabla? Creo que sería una macro que llama a una función que dentro declara las variables poner todo en la tabla y hacerlo externo para que sea posible acceder desde otros archivos de código.

    – Gabriel Magrí

    28 de junio de 2018 a las 4:53


avatar de usuario
Comunidad

La gente a menudo quiere programas para la auto-introspección (o “reflexionar” en la jerga actual). Pero la mayoría de los lenguajes de programación ofrecen poca capacidad (p. ej., Java) o ninguna (C) para reflejar todos los detalles de un programa (nombres de variables, nombres de funciones, tipos, estructuras de expresión, etc.).

Hay una manera de hacer esto para todos idiomas: paso fuera de el idioma y utilizar 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 programas.

Consulte esta respuesta SO para obtener una discusión sobre cómo “obtener nombres de variables” e imprimir valores utilizando un sistema de transformación de programas: rastrear cambios en variables automáticamente

  • ¿Podría decirme un poco más sobre cómo usaría la macro que ayuda a construir la tabla? Creo que sería una macro que llama a una función que dentro declara las variables poner todo en la tabla y hacerlo externo para que sea posible acceder desde otros archivos de código.

    – Gabriel Magrí

    28 de junio de 2018 a las 4:53


Prueba esto.

#define MACRO_VARIABLE_TO_STRING(Variable) ((void) Variable,#Variable)

Código (vacío) La variable es una conversión nula que no es operativa, luego está el operador de coma y la cadena macro. Entonces, el resultado neto es const char * que contiene el nombre de la variable con la verificación del compilador si la variable realmente existe.

Ahora tiene el nombre de su variable y puede usar printf() para imprimir su valor.

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad