2009-10-26 12 views
28

Ich entwickle ein Tool zum Ausgeben von Daten aus Variablen. Ich muss den Variablennamen und auch die Werte ausgeben.Programmatische Möglichkeit, Variablennamen in C zu bekommen?

Meine Lösung: Speichern Sie den Variablennamen als String und geben Sie den "Variablennamen" gefolgt von seinem Wert ein.

Gibt es eine programmatische Möglichkeit, den Variablennamen zu kennen?

Antwort

47

Man könnte so etwas wie dies versuchen:

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

I verwendet this header verwende ich schrieb, als ich zu C neu war, könnte es einige nützliche Ideen enthalten. Zum Beispiel würde dies erlauben Sie einen C-Wert zu drucken und die Formatbezeichner in einem (sowie einige zusätzliche Informationen) zur Verfügung stellen:

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

Wenn Sie C++ verwenden, können Sie den Typ des übergebenen Wert verwenden könnte und es entsprechend ausgeben. Ich kann ein viel lukrativeres Beispiel für das "schöne Drucken" von Variablenwerten liefern, wenn dies der Fall ist.

+0

Das ist eine gute Idee, Dinge innerhalb des Programms zu tun. Erzeugt eine Menge String-Konstanten, das ist sicher. –

+0

Sie sind wahrscheinlich besser dran, es als 'DUMP (varname, format) 'zu definieren und' '% s =" format "\ n" 'in' fprintf' zu verwenden, um mehr Typen zu bearbeiten: 'DUMP (somestring, "% s") 'oder' DUMP (sainint, "% d") '. – caf

+0

Dies ist der übliche Weg um die nicht-introspektive Art von c. Wie Sie sich vorstellen können, hat es seine Grenzen und Fallen, aber es ist ungefähr so ​​gut, wie Sie es tun können, ohne einen eigenen introspektiven Interpreter zu bauen. – dmckee

1

Wenn Ihre ausführbare Datei mit Debuginformationen kompiliert wurde, können Sie diese Informationen möglicherweise abrufen. Wenn nicht, haben Sie wahrscheinlich kein Glück. Sie bauen also einen Debugger? Warum? Vorhandene Debugger für c sind sehr ausgereift. Warum nicht bestehende Werkzeuge verwenden, anstatt das Rad neu zu erfinden?

+0

einige Beispiele für den Debugger zur Laufzeit abzufragen bitte? –

11

In C existieren Variablennamen während des Kompilierungsschritts (und des Verbindungsschritts, wenn die Variable global ist), sind jedoch zur Laufzeit nicht verfügbar. Sie müssen eine Lösung auswählen, die eine literale Zeichenfolge enthält, die den Variablennamen angibt.

1

Es gibt keinen guten Weg, dies innerhalb Ihres Programms zu tun, fürchte ich (abgesehen von Anacrolix 'Antwort). Ich denke, die richtige Lösung für Ihr Problem ist ein Debugger-Skript. In den meisten Debuggern können Sie es sogar so anschließen, dass es jedes Mal ausgeführt wird, wenn der Debugger die Programmausführung unterbricht (Haltepunkt, Sie drücken ^C, usw.) und erhalten bei jeder Interaktion einen Schnappschuss Ihres Programmstatus.

4

Wenn Sie dies für beliebige Variablen tun müssen, dann müssen Sie wahrscheinlich eine Debugger-API verwenden, die der Compiler oder die Plattform bietet (wie DbgHelp unter Windows).

Auf einigen eingebetteten Systemen, an denen ich gearbeitet habe, mussten wir die Werte bestimmter wichtiger Variablen, die uns im Voraus bekannt sind, auf Befehl anzeigen können. Dazu benötigen wir lediglich eine einfache Name/Pointer-Tabelle Früher habe ich nur ein wenig Routine

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


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

Dann, die die Tabelle für den Variablennamen in Frage sucht, und Dumps den Namen und die Daten, auf die durch den Zeiger. Wenn Sie andere Daten als einfache Intarsien ausgeben müssen, können Sie die Struktur so erweitern, dass sie auch einen druckformatierten Formatierer enthält, und den Zeiger auf void* setzen und diesen Junk an snprintf() oder etwas weiterleiten, um die Daten zu formatieren.

Manchmal verwende ich auch ein Makro, das hilft, die Tabelle zu erstellen (möglicherweise auch die Variable deklarieren). Aber um ehrlich zu sein, ich denke, das macht es wirklich nur komplizierter zu verstehen (besonders für jemanden, der sich dem Projekt anschließt - sie haben oft einen kleinen "WTF" -Moment) und vereinfacht die Dinge nicht wirklich.

6

Ich habe tatsächlich einen Code, der tun kann, was Sie wollen. Es verwendet den Präprozessor, um den Variablennamen zu stringulieren, damit Sie ihn ausdrucken können. Es speichert sowohl den Variablennamen und -wert (basierend auf dem Typ) als auch das Speicherlayout für diese Variable.Das folgende Programm zeigt, wie es gemacht wird:

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

Diese Ausgänge:

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 

Und, wenn Sie über die geistige Gesundheit von do {...} while (0) in den Makros fragen, das ist es zu ermöglichen, überall platziert werden in der Code, ohne sich darum kümmern zu müssen, ob genug Klammern vorhanden sind.

3

Die Leute wollen oft, dass Programme sich selbst introspizieren (oder im aktuellen Jargon "reflektieren"). Aber die meisten Programmiersprachen bieten wenig (z. B. Java) oder keine (C) Fähigkeit, um alle Einzelheiten eines Programms (Variablennamen, Funktionsnamen, Typen, Ausdrucksstrukturen usw.) zu reflektieren.

Es gibt eine Möglichkeit, dies für all Sprachen zu tun: Schritt außerhalb der Sprache, und ein Tool, das diese Informationen aus der Sprache zu extrahieren ausgelegt ist. Eine Klasse von Werkzeugen, die dies tun können, wird als Programmtransformationssystem bezeichnet.

Sehen Sie diese SO für eine Diskussion beantworten, wie man „Variablennamen erhalten“ und Werte Druck ein Programm Transformationssystem mit: Trace changes to variables automatically

0

bereits.

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

-Code (void) Variable ist ungültig, Umwandlung, die nicht-op dann gibt der Bediener Komma ist und Makro stringify. Also das Nettoergebnis ist const char * enthält Variablennamen mit Compiler-Check ist Variable wirklich existiert.

Jetzt haben Sie den Namen Ihrer Variablen und Sie können printf() verwenden, um seinen Wert zu drucken.

3

Shorter Art und Weise:

#define GET_VARIABLE_NAME(Variable) (#Variable) 

Test:

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