【问题标题】:Can I access variables using a list of their names dynamically?我可以使用变量名称列表动态访问变量吗?
【发布时间】:2018-09-26 05:38:04
【问题描述】:

我有一个变量列表char [][20] ls = {"var_1", "var_2", ... , ""}

这是结构struct {char var1[10], ...} my_struct;的字段名称

结构体中的变量都是char[],长度在变化。 该列表本身是 const 并且不应在运行时更改。

我想以某种通用的方式在循环中访问这些变量。而不是调用myfunc(my_struct.var1); myfunc(my_struct.var2);等等,我宁愿有:

for (char * p = ls[0]; *p; p += sizeof(ls[0]))
{
  myfunc(my_struct.{some magic that would put var_1 / var_2 here});
}

但我想这是不可能的,因为循环是在运行时执行的,并且变量名需要在编译时可用。

我是正确的还是可以在这里做些什么? (不一定是这样,只是想知道我是否可以将这个例程打包成一个不错的循环)

【问题讨论】:

  • 所有字段都具有相同类型吗?
  • 它们都是不同长度的char[]。我可以将所有字段更改为设置长度,如果这可以以某种方式提供帮助(尽管我不明白如何......)
  • 表是const 还是可以在运行时改变?
  • 在问题正文中编辑了您的 cmets 的答案
  • 我认为你需要在 C 中实现 associative array

标签: c


【解决方案1】:

由于所有成员都是相同类型的数组,您可以为每个成员创建一个地址数组并循环遍历:

char *my_struct_addrs[] = { my_struct.var1, my_struct.var2, ... };
int i;
for (i=0; i < sizeof(my_struct_addrs) / sizeof(my_struct_addrs[0]); i++) {
    myfunc(my_struct_addrs[i]);
}

由于每个数组的大小都不同,因此您需要注意不要超出每个数组的范围。您可以通过跟踪每个字段的大小并将其传递给函数来解决此问题:

struct addr_list {
    char *addr;
    int len;
};

struct addr_list my_struct_addrs[] = { 
    { my_struct.var1, sizeof(my_struct.var1) },
    { my_struct.var2, sizeof(my_struct.var2) },
    ...
};

int i;
for (i=0; i < sizeof(my_struct_addrs) / sizeof(my_struct_addrs[0]); i++) {
    myfunc(my_struct_addrs[i].addr, my_struct_addrs[i].len);
}

【讨论】:

  • @dbush - 搜索结构数组不是 OP 要求的语言功能
  • @PeterJ_01 但是它确实帮助我实现了我的需要。
  • 注意:除非有很好的理由 len 应该是 size_tifor 循环内声明
【解决方案2】:

假设你有类似的东西

const char* ls[] = {"var_1", "var_2", ""};

此列表与结构数据没有紧密耦合(如果是这样,您可以使用 dbush 的答案),但无论出于何种原因,它都是一个单独的项目。

然后,稍微笨拙但定义明确的版本是使用查找表。创建两个查找表,一个带有字符串,一个带有偏移量:

#include <stddef.h>

typedef struct
{
  int var_1;
  int var_2;
} my_struct_t;

static const char* VAR_STRINGS[] =
{
  "var_1",
  "var_2",
  ""
};

static const size_t VAR_OFFSET[] =
{
  offsetof(my_struct_t, var_1),
  offsetof(my_struct_t, var_2),
};

然后执行index = search_in_VAR_STRINGS_for(ls[i]); 之类的操作来获取索引。 (遍历所有项目,或使用二进制搜索等)。那么下面的代码实际上是合法且定义明确的:

unsigned char* ptr = (unsigned char*)&my_struct;
ptr += VAR_OFFSET[index];
int var_1 = *(int*)ptr;

这考虑了填充,并且 C11 6.3.2.3/7 保证指针算术正常:

当指向对象的指针转换为指向字符类型的指针时, 结果指向对象的最低寻址字节。的连续递增 结果,直到对象的大小,产生指向对象剩余字节的指针。

并且由于真正存储在该地址(有效类型)的内容确实是int,因此 C11 6.5/7(“严格别名”)保证变量访问正常:

一个对象的存储值只能由具有以下之一的左值表达式访问 以下类型:
— 与对象的有效类型兼容的类型,

但显然需要进行各种错误处理以检查某些内容是否超出范围。

【讨论】:

    猜你喜欢
    • 2012-07-27
    • 2012-11-22
    • 2019-06-08
    • 1970-01-01
    • 1970-01-01
    • 2022-01-18
    • 2017-11-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多