C - 将字符串转换为变量名

5

如何将一个字符串转换为变量名?例如,我有一个字符串列表:

     "str1", "str2", "str3", etc.

还有一个结构:

struct my_struct {  
       int str1;  
       int str2;  
       int str3;  
} m = {5, 10, 15, ... etc};  

如果给定一个字符串"str2",我想要打印与该名称相关联的变量m.str2。C语言有任何方法可以实现吗?

谢谢!


除非您编写代码,否则无法以语言定义的方式访问 m.str2 ,给定m和字符串 "str2"。C语言不提供本地反射支持。 - WhozCraig
谢谢你的回答。我试图做"字符串化"的相反操作,就像gcc手册中所示:https://gcc.gnu.org/onlinedocs/cpp/Stringification.html。 - user2511788
7个回答

9
这在C语言中是不可能实现的。
查看此问题以获取更多详细信息。 如何在C语言中返回变量名并分配返回的变量值 引用Wichert的话,“我建议您重新考虑要解决的问题,并检查是否有更好的方法来解决它。也许使用数组、映射或哈希表可能是适合您的替代方法。”

8
在C语言中,你不能动态创建变量或符号名称

3
这是一种方法。
if ( strcmp(str, "str2") == 0 )
{
   // Use m.str2
}

如果有数百个变量,那就会成为一个问题。在这种情况下,您将不得不想出其他机制。


我有数百个变量,所以这不会扩展。 - user2511788
1
@user2511788 使用宏或借助其他程序生成一些代码。你只需要做一次即可。 - M.M

2

#define get_val(x) (m.str##x)似乎是实现这一目的的方法 - ##是一个标记粘贴运算符,因此要使用这个宏,你只需要调用它定义的函数,并将字符串名称中的数字作为参数传递给它,get_val(2)


1

我建议一种稍微简单一些的解决方案,尽管可能不是最有效的。

这是我与我的教授商量后在一个项目中想出来的解决方案。

本质上,字符串只是ASCII字符,包含变量名称的C文件也可以以同样的方式考虑。

因此,假设您有一个字符串列表,您想将其转换为整数变量名称。

首先,在一个头文件中定义您的结构,该文件可以被目录中的所有文件访问,例如“struct.h”。

第一步是将字符串名称转换为它们各自的整数。

只需创建一个名为variable_names.h的空头文件,包含struct.h,然后在主文件中一次性调用以下循环:

const char *strings[] = {"str1", "str2", ... }
fp = fopen("variable_names.h", "a");
fprintf(fp, "#ifndef FILE1_H \n");
fprintf(fp, "#define FILE1_H \n");
fprintf(fp, "extern int* m_integers = {");
int i;
for(i = 0; i < sizeof(strings) - 1; i++){ fprintf(fp, "m.%s,", strings[i]);}
fprintf(fp, "m.%s } ", strings[i+1])
fprintf(fp, "#endif");

现在您的结构体中的字符串名称和值之间有一个线性映射,通过m_integers数组实现。接下来需要创建一些映射,将字符串名称输入并将其指向这个整数。我将使用UTHASH,但肯定还有其他方法。
因此,在您的主文件中,
#include "uthash.h"
#include "variable_names.h"
...

struct opcode_table{
     char* opcode_key;
     int opcodes_val;
     UT_hash_handle hh;
 };
struct opcode_table *mapping = NULL;

struct opcode_table* s = NULL;
for (int i = 0; i  < opcode_size; i++){
  s = (struct opcode_table*) malloc(sizeof(*s)); 
  s->opcodes_key = strings[i]; // the string 
  s->opcode_val = m_integers[i]; // the integer
  HASH_ADD(hh,mapping, opcodes_key, sizeof(int),s);
}

^请对代码手下留情,这只是一个大概的示例。我相信会有一些错误,但总体来说,我认为这应该可以工作。

简而言之,这个想法本质上是将ascii字符"m.string1"写入外部文件,一旦写入,通过结构定义解释为整数,从而得到所需的结果。现在,您只需要在哈希表中查找字符串,就可以在结构中获取整数。

此外,如果有人发现更好的方法或者这种方法存在缺陷,请提供反馈。谢谢!


0
你想要的是Smalltalk语言在1980年代使用的解释器和Python仍然使用的通过C语言中的TTY命令Shell程序从字符串字符创建对象变量的方法。
我们通过使用嵌套结构体来实现这些操作。但实际的变量名称并没有被声明。它们通过在结构体中存储的字符名称进行条件搜索匹配,如果不存在,则创建它们。
如果它在结构体列表中存在,它将有条件地查找它及其存储的值或根据程序设计的要求分配其值。
最好理解这个例子是使用Token(tok),(s),(t),(e)和其他几个作为令牌流读入的前瞻符号。
if (tok == "IDENT";) {

当它发现一个标识符(来自lex的变量标签)令牌时,它会向前查找并获取变量名称,然后创建它,如果其前面包含另一个变量,则执行计算,例如"CHAR"或"FLOAT"(对于double等)。
现在它所做的是有条件地将所有内容设置为正在被tok令牌流分配的结构列表中读取的内容。
"CHAR" "x" "EQUALS" "INT" "5" "NEWL(for \N)" "CHAR" "y" "EQUALS" "INT" "5" "NEWL" "PRNT" "CHAR" "x" "NEWL"。
因此,基本上所有通过void函数传递的变量都有条件地被分配到结构列表中,并且同样由它们存储其值。
而且,你不需要匹配存储的变量名,只需要从单个tok变量及其前瞻中进行匹配即可。
struct Var v; //--declared in .h then--
if(tok == 'CHAR') //--and-- 
v = {tok2, s, t} //

"tok2" 是你的变量字符名称,"s" 和 "t" 是用来获取、计算和/或分配它们的前瞻。基本上,Python 使用一个名为 tok 的 C 变量来命名它们所有。然后匹配使它们都具有动态性和易于 Python 使用。atoi 和 strtod 也可以在运行时进行整数和双精度转换。这是高级的东西。

整个过程在早期 ANCI C 中被称为“扫描器”和“计算器”。研究 Dennis Ritchie 和 Tobias Shrighner。Tobias 实际上曾经在几个解释器上工作过。


0

这里有一种方法,请查看我编写的示例代码。我使用了整数指针ptr来实现这个。

#include <stdio.h>
#include <string.h>
const char *s[] = {"str1", "str2", "str3", "str4", "str5", "str6", "str7", "str8", "str9", "str10"};
struct temp
{
    int str1;
    int str2;
    int str3;
    int str4;
    int str5;
    int str6;
    int str7;
    int str8;
    int str9;
    int str10;
}m = {10, 20, 30, 40, 50, 60, 70, 80, 90, 100};

main()
{
    char str[10];
    int *ptr;
    int i;
    ptr = &m.str1;
    printf("enter string: \t");
    scanf("%s", str);
    for(i=0;i<10;i++)
    {
        if(strcmp(str,s[i]) == 0)
        {
            break;
        }
    }
    printf("value = %d\n", *(ptr+i));

}

如果有任何错误,请纠正我。


我想找一种避免使用strcmp的方法,因此检查是否有任何预处理器技巧。 - user2511788
如果您想在运行时提供字符串,则预处理器技巧将无法起作用。 - venki

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接