2009-10-26 17 views
28

Sto sviluppando uno strumento per scaricare dati da variabili. Ho bisogno di scaricare il nome della variabile, e anche i valori.Modo programmatico per ottenere il nome della variabile in C?

La mia soluzione: memorizzare il nome della variabile come stringa e stampare il "nome della variabile", seguito dal suo valore.

Esiste un modo programmatico per conoscere il nome della variabile?

risposta

47

si potrebbe provare qualcosa di simile:

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

ho utilizzato this header ho scritto, quando ero di nuovo da C, che potrebbe contenere alcune idee utili. Per esempio, questo permetterebbe di stampare un valore di C e di fornire l'identificatore di formato in un unico (così come alcune informazioni aggiuntive):

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

Se stai usando C++, è possibile utilizzare il tipo di valore passato ed emetterlo in modo appropriato. Posso fornire un esempio molto più lucrativo su come "stampare bene" i valori delle variabili se questo è il caso.

+0

È una buona idea fare cose dall'interno del programma. Crea un gruppo di costanti stringa, questo è sicuro. –

+0

Probabilmente stai meglio definendolo come 'DUMP (varname, format)' e usando '"% s = "format" \ n "' nel 'fprintf', permettendogli di lavorare su più tipi:' DUMP (somestring, "% s") 'o' DUMP (someint, "% d") '. – caf

+0

Questo è il solito modo per aggirare la natura non introspettiva di c. Come puoi immaginare, ha i suoi limiti e le sue trappole, ma è meglio che tu possa fare senza costruire il tuo interprete introspettivo. – dmckee

1

Se il file eseguibile è compilato con informazioni di debug, è possibile ottenere queste informazioni. In caso contrario, probabilmente sei sfortunato. Quindi stai costruendo un debugger? Perché? I debugger esistenti per c sono molto maturi. Perché non utilizzare gli strumenti esistenti invece di reinventare la ruota?

+0

alcuni esempi di interrogare il debugger in fase di esecuzione per favore? –

11

In C, i nomi delle variabili esistono durante il passo di compilazione (e il passaggio di collegamento, se la variabile è globale), ma non sono disponibili in fase di esecuzione. È necessario scegliere una soluzione che prevede una stringa letterale che indica il nome della variabile.

1

Non c'è un buon modo per farlo dall'interno del tuo programma, temo (a parte la risposta di Anacrolix). Penso che la soluzione giusta al tuo problema sia uno script di debugger. Nella maggior parte dei debugger, puoi persino collegarlo per eseguire ogni volta che il debugger interrompe l'esecuzione del programma (punto di interruzione, premi ^C, ecc.) E ottieni un'istantanea dello stato del tuo programma ogni volta che interagisci con esso.

4

Se è necessario eseguire questa operazione per variabili arbitrarie, sarà probabilmente necessario utilizzare un'API debugger fornita dal compilatore o dalla piattaforma (come DbgHelp su Windows).

Su alcuni sistemi embedded su cui ho lavorato, dovevamo essere in grado di visualizzare a comando i valori di alcune importanti variabili conosciute in anticipo e per fare tutto ciò di cui abbiamo bisogno è una semplice tabella Name/pointer :

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


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

Poi ho solo usato un po 'di routine che cerca la tabella per il nome della variabile in questione, e ne mostra il nome ei dati a cui punta il puntatore. Se è necessario eseguire il dump di dati diversi da plain ints, è possibile estendere la struttura per contenere anche un formattatore di stile printf e modificare il puntatore in modo da essere un void* e passare tale junk a snprintf() o qualcosa per formattare i dati.

A volte userò anche una macro che aiuta a costruire la tabella (probabilmente anche dichiarando la variabile). Ma per essere onesti, penso che ciò rende davvero più complicata la comprensione (specialmente per qualcuno che si unisce al progetto - spesso hanno un piccolo momento "WTF?") E in realtà non semplifica molto le cose.

6

In realtà ho un codice che può fare ciò che vuoi. Usa il preprocessore per stringere il nome della variabile per permetterti di stamparlo. Scarica sia il nome e il valore della variabile (in base al tipo) sia il layout della memoria per quella variabile.Il seguente programma mostra come si fa:

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

Questo uscite:

i: 42 
>>  +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +a +b +c +d +e +fabcdef 
>> 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 +fabcdef 
>> 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 +fabcdef 
>> 0000 61 b6 16 61 2a 00 00 00 48 65 6c 6c 6f 00 0d 61 a..a*...Hello..a 

E, se vi state chiedendo circa la sanità mentale dei do {...} while (0) nelle macro, che è per consentirgli di essere collocato in qualsiasi punto il codice senza doversi preoccupare se hai abbastanza graffe che lo circondano.

3

Le persone spesso desiderano programmi per auto-introspezione (o "riflettere" nel gergo corrente). Ma la maggior parte dei linguaggi di programmazione offre poche (ad esempio, Java) o nessuna (C) capacità di riflettere su tutti i dettagli di un programma (nomi di variabili, nomi di funzioni, tipi, strutture di espressione, ecc.).

C'è un modo per fare questo per tutta lingue: passo di fuori la lingua, e utilizzare uno strumento che è stato progettato per estrarre queste informazioni dal linguaggio. Una classe di strumenti che può fare ciò è chiamata sistema di trasformazione del programma.

Vai a questa SO rispondere per una discussione su come "ottenere i nomi delle variabili" e valori di stampa attraverso un sistema di programma di trasformazione: Trace changes to variables automatically

0

Prova questa.

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

Codice (void) variabile è la conversione vuoto che è no-op poi c'è l'operatore virgola e macro stringa i. Quindi il risultato netto è const char * contenente il nome della variabile con il controllo del compilatore la variabile esiste realmente.

Ora si ha il nome della variabile e si può usare printf() per stampare il suo valore. modo

3

Shorter:

#define GET_VARIABLE_NAME(Variable) (#Variable) 

prova:

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