C 宏,用于从数字变量值生成令牌



如何定义一个 C 宏,该宏将根据传递给该函数的变量的值生成变量名称(标记)? 在下面的示例中,查找 MEMBER 宏的有效版本。

例如,给定一个结构,如下所示,我需要定义一个宏,该宏将根据传递给函数的变量的值生成变量名称。

struct foo {
uint32_t bar0_data;
uint32_t bar0_status;
uint32_t bar1_data;
uint32_t bar1_status;
...
};
#define MEMBER(x, n, f) x -> bar ## n ## _ ## f
void write_val(struct foo *foo, int which_bar)
{
MEMBER(foo, which_bar, data) = 1;
MEMBER(foo, which_bar, status) = 2;
}

这适用于在此主题上具有不同变体的巨型结构,因此使用成员结构数组定义新结构不是一种选择。

C 不允许你以这种方式创建动态名称。

可以使用查找表对其进行模拟。

但是,您实际上只想从运行时数据中找到foo中的特定字段。这可以通过多种方式完成。例如,开关语句。

switch (which_bar) {
case 0: foo->bar0_data = 1;
foo->bar0_status = 1;
break;
...
}

如果您希望使用文本表,则可以存储字段的偏移量。

offset_t bar_data[] = {
offsetof(struct foo, bar0_data),
offsetof(struct foo, bar1_data),
...
};
offset_t bar_status[] = {
offsetof(struct foo, bar0_status),
...
};
#define BAR_DATA(FOO, WHICH) 
(*(uint32_t *)((char *)(FOO) + bar_data[WHICH]))
#define BAR_STATUS(FOO, WHICH) 
(*(uint32_t *)((char *)(FOO) + bar_status[WHICH]))
BAR_DATA(foo, which_bar) = 1;
BAR_STATUS(foo, which_bar) = 1;

但是,似乎通过定义一个结构来表示"bar",并在foo中定义它们的数组会更好。

struct bar {
uint32_t data;
uint32_t status;
};
struct foo {
struct bar bar[MAX_BARS];
};
foo->bar[which_bar].data = 1;
foo->bar[which_bar].status = 1;

您必须考虑允许您"执行"动态生成的文本的语言(如JavaScript)。C的不同之处在于,从源文本到运行二进制文件的转换发生在以下步骤中:

  1. 运行pre-processor- 这是使用宏扩展和其他规则(如#include指令)修改程序文本的地方
  2. 运行compiler- 这会将步骤 1 的结果转换为机器代码(无论是通过使用Assembler语言的中间步骤还是直接
  3. )
  4. 将生成的对象文件与库链接(如有必要),解析所有外部符号并生成您运行的"最终"二进制文件(或静态/动态库 - 取决于您的输出)

在任何情况下,运行时行为都发生在pre-processor步骤之后,因此您正在寻找的内容在C语言中是不可能的(除了编写一个重新编译并重新启动自身的自修改程序)

FWIW 发现,假设每个实例都以固定偏移量出现,实现此宏的一种方法是:

#define DELTA(m1, m2) (offsetof(foo_t, m2) - offsetof(foo_t, m1))
#define MEMBER(x, n, f)                                 
*(uint32_t *)(((uint8_t *)& x -> bar0_ ## f) +      
(DELTA(bar0_ ## f, bar1_ ## f) * n))

它不会像最初请求的那样生成变量名称标记,但可用于访问值,而无需生成名称。

相关内容

最新更新