C程序将变量名称作为输入和打印值
我有一个程序test.c
int global_var=10; printf("Done");
我做到了
gcc -g test.c -o test
我的查询是否有一种方法可以将变量名称作为参数(比如“global_var”)并打印该值。
谢谢
通常,无法通过名称在运行时访问全局变量。 有时,它可能取决于操作系统以及如何调用编译器。 我仍然假设您要取消引用全局变量,并且您知道它的类型。
然后在Linux和其他一些系统上,你可以使用带有NULL
路径的dlopen(3) (获取可执行文件的句柄),然后在全局变量名上使用dlsym
来获取它的地址; 然后,您可以将void*
指针强制转换为适当类型的指针并取消引用它。 请注意,您需要知道类型(或者至少有一个约定来对其名称中的变量类型进行编码; C ++正在使用名称修改 )。 如果您使用调试信息(即使用gcc -g
)进行编译和链接,则类型信息位于ELF可执行文件的DWARF部分中,因此可以通过某种方式获取它。
如果使用-rdynamic
和-ldl
链接可执行文件,则此方法有效
另一种可能性是使用您自己的MELT扩展来定制您最近的GCC ,该扩展将记住并稍后重新使用一些编译器内部表示(即与全局变量相关的GCC 树 )。 使用MELT register_finish_decl_first
函数在声明上注册处理程序。 但这需要一些工作(编码MELT扩展)。
使用预处理器技巧
您可以使用(可移植的)预处理器技巧来实现您的目标(在运行时按名称访问变量)。
最简单的方法可能是定义和遵循您自己的约定。 例如,您可以拥有自己的globvar.def
头文件,其中只包含类似的行
/* file globvar.def */ MY_GLOBAL_VARIABLE(globalint,int) MY_GLOBAL_VARIABLE(globalint2,int) MY_GLOBAL_VARIABLE(globalstr,char*) #undef MY_GLOBAL_VARIABLE
并且您采用所有全局变量都在上面的globvar.def
文件中的globvar.def
。 然后你会多次 #include "globvar.def"
。 例如,在全局标题中,将MY_GLOBAL_VARIABLE
展开为某些extern
声明:
/* in yourheader.h */ #define MY_GLOBAL_VARIABLE(Nam,Typ) extern Typ Nam; #include "globvar.def"
在你的main.c
你需要一个类似的技巧来声明你的全局变量。
在其他地方,您可以定义一个函数来按名称获取整数变量:
/* return the address of global int variable or else NULL */ int* global_int_var_by_name (const char*name) { #define MY_GLOBAL_VARIABLE(Nam,Typ) \ if (!strcmp(#Typ,"int") && !strcmp(name,#Nam)) return (int*)&Nam; #include "globvar.def" return NULL; }
等等……我正在使用宏参数的字符串化 。
这样的预处理器技巧纯粹是标准C,可以与任何符合C99的编译器一起使用。
不,C没有内省 。 一旦编译器生成了代码,程序就无法查找变量名。
通常解决这些问题的方法是通过拥有需要按名称查找的所有特殊变量的集合,包含实际名称作为字符串和变量it self。
通常它是一组结构,类似于
struct { const char *name; int value; } variables[] = { { "global_var", 10 } };
然后,程序可以查看数组variables
以搜索"global_var"
并使用(或更改)结构中的值。
一般答案:不可以。变量名与其字符串表示之间没有任何关联(尽管如此,您可以在编译时使用预处理器获取变量名的字符串表示)。
对于具有外部链接的标识符,有(平台相关的)方式:参见例如POSIX系统的dlsym
。
您可以使用调试信息进行编译,并通过输入中的名称访问(大多数)变量。 除非你真的写了类似调试器的东西,否则这将是一个糟糕的设计(即使这样,你也不会访问调试器本身使用的变量,而是调试正在调试的程序)。
最后,您可以实现自己的查找表映射,从字符串表示到值。
不。我们只有变量名称,所以人类不会感到困惑。 将程序转换为程序集并最终转换为机器代码后,计算机并不关心您为变量命名的内容。
或者,您可以使用一种结构,在该结构中将值和名称存储为字符串:
struct tag_name { char *member1; int member2; };