Programmatic way to get variable name in C?
Asked Answered
S

10

45

I am developing a tool to dump data from variables. I need to dump the variable name, and also the values.

My solution: Store variable name as a string, and print the "variable name", followed by its value.

Is there any programmatic way to know the variable name?

Scope answered 26/10, 2009 at 4:42 Comment(0)
J
68

You could try something like this:

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

I used to use this header I wrote, when I was new to C, it might contain some useful ideas. For example this would allow you to print a C value and provide the format specifier in one (as well as some additional information):

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

If you're using C++, you could use the type of the passed value and output it appropriately. I can provide a much more lucrative example for how to "pretty print" variable values if this is the case.

Jews answered 26/10, 2009 at 4:56 Comment(6)
That's a good idea to do things from inside the program. Creates a bunch of string constants, that's for sure.Uncaused
You are probably better off defining it as DUMP(varname, format) and using "%s = " format "\n" in the fprintf, allowing it to work on more types: DUMP(somestring, "%s") or DUMP(someint, "%d").Maller
This is the usual way around the non-introspective nature of c. As you might imagine, it has its limits and traps, but it is about as good as you can do without building your own introspective interpreter.Mycostatin
In DUMP Why are you substituting #varname with %s? Just use implicit string concatenation: #define DUMP(Var) (fprintf(stderr, #Var "= %p", Var))Flinch
@Jack Kelly: You can't be sure what exactly will be given in var, either way it has to be printed as a string. This wouldn't work nicely if var was 22 % 7Jews
The header is no longer available, could you maybe post a new link? Or maybe add the headerThrilling
S
13

Shorter way:

#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;
}
Styracaceous answered 29/9, 2016 at 16:36 Comment(1)
Nice and clean.Serviceman
W
11

In C, variable names exist during the compile step (and the link step, if the variable is global), but are not available at runtime. You must choose a solution that involves a literal string indicating the variable name.

Windproof answered 26/10, 2009 at 4:47 Comment(0)
B
8

I actually have some code which may do what you want. It uses the preprocessor to stringize the variable name to allow you to print it out. It dumps both the variable name and value (based on the type) and the memory layout for that variable. The following program shows how it's done:

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

This outputs:

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

And, if you're wondering about the sanity of do {...} while (0) in the macros, that's to enable it to be placed anywhere in the code without having to worry about whether you have enough braces surrounding it.

Bridesmaid answered 26/10, 2009 at 5:39 Comment(0)
C
4

If you need to do this for arbitrary variables then you'll probably need to use a debugger API that the compiler or platform provides (like DbgHelp on Windows).

On some embedded systems I worked on we've needed to be able to display on command the values of certain important variables that are known ahead of time, and to do that all that we need is a simple Name/pointer table:

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


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

Then I just used a little routine that searches the table for the variable name in question, and dumps the name and the data pointed to by the pointer. If you need to dump data other than plain ints, you can extend the structure to also hold a printf-style formatter and change the pointer to be a void* and pass that junk to snprintf() or something to format the data.

Sometimes I'll also use a macro that helps build the table (possibly also declaring the variable). But to be honest, I think that that really just makes it more complex to understand (especially for someone new joining the project - they often have a small "WTF?" moment) and doesn't really simplify things much.

Castillo answered 26/10, 2009 at 5:11 Comment(1)
Could you tell me a little bit more about how would you use the macro that helps building the table? I think it would be a macro that calls a function that inside declare the variables put all of it in the table and make it extern in order to make it possible to access from other code files.Rhinology
V
3

People often want programs to self-introspect (or "reflect" in current jargon). But most programming languages offer little (e.g., Java) or none (C) capability to reflect on all the details of a program (variable names, function names, types, expression structures, etc.).

There's a way to do this for all languages: step outside the language, and use a tool that is designed to extract that information from the language. A class of tool that can do this is called a program transformation system.

See this SO answer for a discussion of how to "get variable names" and print values using a program transformation system: Trace changes to variables automatically

Vulnerary answered 2/11, 2010 at 9:15 Comment(0)
T
2

Try this.

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

Code (void) Variable is void conversion which is no-op then there is the comma operator and macro stringify. So the net result is const char* containing variable name with compiler check is variable really exists.

Now you have the name of your variable and you can use printf() to print its value.

Thamora answered 6/9, 2016 at 13:6 Comment(0)
M
2

Despite the very precise answer from @Matt Joiner, I wanna write a full short code exemplifying this just to see how simple it is using #define macro

#include <stdio.h>
#define val_name(v)#v
int main()
    {
    char a[]="hello";
    printf("%s %s",a,val_name(a));
    }

output: hello a

Medullated answered 17/2, 2019 at 13:55 Comment(0)
S
1

If your executable is compiled with debugging information, you may be able to get this info. If not, you're probably out of luck. So you're building a debugger? Why? Existing debuggers for c are very mature. Why not use existing tools instead of re-inventing the wheel?

Salamis answered 26/10, 2009 at 4:46 Comment(1)
some examples of interrogating the debugger at runtime please?Jews
U
1

There isn't a good way to do that from inside your program, I'm afraid (aside from Anacrolix' answer). I think the right solution to your problem is a debugger script. In most debuggers, you can even hook it up to run every time the debugger interrupts program execution (breakpoint, you hit ^C, etc) and get a snapshot of your program state every time you interact with it.

Uncaused answered 26/10, 2009 at 4:53 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.