在C中获取变量名称的编程方法?

发布于 2024-08-08 17:19:47 字数 110 浏览 12 评论 0原文

我正在开发一个工具来转储变量中的数据。 我需要转储变量名称以及值。

我的解决方案:将变量名称存储为字符串,并打印“变量名称”,后跟其值。

有没有任何编程方法可以知道变量名称?

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(10

云淡风轻 2024-08-15 17:19:47

你可以尝试这样的事情:

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

我曾经使用 这个头 我写的,当我刚接触 C 时,它可能包含一些有用的想法。例如,这将允许您打印 C 值并在其中提供格式说明符(以及一些附加信息):

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

如果您使用 C++,则可以使用传递值的类型并适当地输出它。如果是这种情况,我可以提供一个更有利可图的示例来说明如何“漂亮地打印”变量值。

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.

阳光的暖冬 2024-08-15 17:19:47

更短的方法:

#define GET_VARIABLE_NAME(Variable) (#Variable)

测试:

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

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;
}
像极了他 2024-08-15 17:19:47

在 C 中,变量名称存在于编译步骤(以及链接步骤,如果变量是全局变量)期间,但在运行时不可用。您必须选择一个包含指示变量名称的文字字符串的解决方案。

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.

你的他你的她 2024-08-15 17:19:47

我实际上有一些代码可以做你想要的。它使用预处理器将变量名称字符串化,以便您将其打印出来。它转储变量名称和值(基于类型)以及该变量的内存布局。下面的程序展示了它是如何完成的:

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

输出:

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

而且,如果您想知道宏中 do {...} while (0) 的合理性,那就让它能够被放置代码中的任何位置,而不必担心是否有足够的大括号围绕它。

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.

栖迟 2024-08-15 17:19:47

如果您需要对任意变量执行此操作,那么您可能需要使用编译器或平台提供的调试器 API(例如 Windows 上的 DbgHelp)。

在我工作的一些嵌入式系统上,我们需要能够在命令上显示提前已知的某些重要变量的值,要做到这一点,我们需要的是一个简单的名称/指针表:

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


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

然后我只需使用一个小例程在表中搜索相关变量名称,并转储名称和指针指向的数据。如果您需要转储除普通整数以外的数据,您可以扩展该结构以同时保存 printf 样式格式化程序,并将指针更改为 void* 并将该垃圾传递给 snprintf( ) 或格式化数据的东西。

有时我还会使用宏来帮助构建表(也可能声明变量)。但说实话,我认为这确实让理解变得更加复杂(特别是对于新加入该项目的人来说 - 他们经常会有一个小的“WTF?”时刻)并且并没有真正简化事情。

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.

病毒体 2024-08-15 17:19:47

人们常常希望程序能够自我反省(或者用当前的行话来说是“反思”)。但大多数编程语言提供很少(例如,Java)或不提供(C)能力来反映程序的所有细节(变量名称、函数名称、类型、表达式结构等)。

有一种方法可以对所有语言执行此操作:进入该语言外部,并使用旨在从该语言中提取该信息的工具。可以做到这一点的一类工具称为程序转换系统。

有关如何使用程序转换系统“获取变量名称”和打印值的讨论,请参阅此 SO 答案:
自动跟踪变量更改

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

心凉怎暖 2024-08-15 17:19:47

试试这个。

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

代码(void)变量是void转换,是无操作的,然后有逗号运算符和宏stringify。所以最终结果是 const char* 包含变量名称,编译器检查变量是否确实存在。

现在您有了变量的名称,并且可以使用 printf() 打印其值。

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.

岁月流歌 2024-08-15 17:19:47

尽管 @Matt Joiner 给出了非常精确的答案,但我想编写一个完整的简短代码来举例说明这一点,只是为了看看使用 #define 是多么简单宏

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

输出:你好

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

情栀口红 2024-08-15 17:19:47

如果您的可执行文件是使用调试信息编译的,您也许可以获得此信息。如果没有,你可能就不走运了。那么你正在构建一个调试器?为什么?现有的 C 调试器非常成熟。为什么不使用现有工具而不是重新发明轮子呢?

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?

很快妥协 2024-08-15 17:19:47

恐怕没有一个好的方法可以从你的程序内部做到这一点(除了 Anacrolix 的答案)。我认为解决您问题的正确方法是调试器脚本。在大多数调试器中,您甚至可以将其挂起以在每次调试器中断程序执行(断点、命中 ^C 等)时运行,并在每次与其交互时获取程序状态的快照。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文