C程序以输入变量名,并打印其值。

14 浏览
0 Comments

C程序以输入变量名,并打印其值。

我有一个程序test.c\n

int global_var=10;
printf("Done");

\n我执行了\n

gcc -g test.c -o test

\n我的问题是\n有没有办法让我以参数的方式获取变量名(比如说\"global_var\")并打印出其值。\n谢谢

0
0 Comments

在C程序中,无法直接根据变量名获取其值的字符串表示。但是,可以通过预处理器在编译时获取变量名的字符串表示。对于具有外部链接的标识符,可以使用平台相关的方法来获取变量名。例如,在POSIX系统中可以使用dlsym

另一种方法是使用调试信息进行编译,并通过输入的变量名来访问(大多数)变量。然而,除非你真的要编写类似于调试器的东西,否则这将是一个可怕的设计(即使在这种情况下,你也不能访问调试器本身使用的变量,而是调试程序本身使用的变量)。

最后,你可以实现自己的查找表,将字符串表示与对应的值进行映射。这样,通过输入变量名,你就可以获取相应的值。

0
0 Comments

在一般情况下,不可能通过变量名在运行时访问全局变量。有时,这可能取决于操作系统和编译器的调用方式。假设您仍然想要解引用全局变量,并且知道其类型。

然后在Linux和其他一些系统上,您可以使用dlopen(3)NULL路径(以获取可执行文件的句柄),然后使用dlsym在全局变量名称上获取其地址;然后,您可以将void*指针转换为适当类型的指针并对其进行解引用。请注意,您需要知道类型(或至少在名称中编码变量的类型的约定;C++正在使用名称修饰)。如果您使用调试信息(即使用gcc -g编译和链接),则类型信息位于您的ELF可执行文件的DWARF部分中,因此有一些方法可以获取它。

这适用于使用-rdynamic链接可执行文件并使用-ldl的情况。

另一种可能性是使用您自己的MELT扩展自定义最新版本的GCC,该扩展将记住并稍后重新使用一些编译器内部表示(即与全局变量相关的GCC Tree-s)。使用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文件中的约定。然后,您将#include "globvar.def" 多次。例如,在全局头文件中,将MY_GLOBAL_VARIABLE扩展为某个extern声明:

 /* in yourheader.h */
 #define MY_GLOBAL_VARIABLE(Nam,Typ) extern Typ Nam;
 #include "globvar.def"

在您的main.c中,您需要类似的技巧来声明全局变量。

另外,您可以定义一个通过名称获取整数变量的函数:

 /* 返回全局int变量的地址,否则返回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标准的编译器上工作。

0
0 Comments

C语言没有内省(introspection)功能。一旦编译器生成了代码,程序就无法查找变量名。

通常解决这类问题的方式是通过一个包含需要按名称查找的所有特殊变量的集合来实现,其中包含实际名称字符串和变量本身。

通常它是一个结构体数组,类似于

struct
{
    const char *name;
    int value;
} variables[] = {
    { "global_var", 10 }
};

然后程序可以通过遍历数组variables来搜索"global_var"并使用(或更改)结构体中的值。

0