C宏从数值变量值生成令牌

时间:2018-04-20 19:22:02

标签: c c-preprocessor

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

e.g。给定下面的结构,我需要定义一个宏,它将根据传递给函数的变量值生成变量名。

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;
}

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

3 个答案:

答案 0 :(得分:1)

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

  1. 使用宏扩展和其他规则(如pre-processor指令)运行#include - 程序文本已修改的地方
  2. 运行compiler - 这会将步骤1的结果转换为机器代码(无论是通过使用Assembler语言的中间步骤还是直接执行)
  3. 将生成的目标文件与库(如有必要)链接,解析所有外部符号并生成" final"您运行的二进制文件(或静态/动态库 - 取决于您的输出)
  4. 在任何情况下运行时行为都会在<{1}}步骤之后发生 way ,因此pre-processor无法找到您要查找的内容语言(缺少编写自我修改程序,重新编译并重新启动自己)

答案 1 :(得分:1)

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

您可以使用查找表来模拟它。

但是,您实际上只想从运行时数据中找到Output0Buffer.memberOf= result.Properties["memberOf"][0].ToString(); 中的特定字段。这可以通过几种方式完成。例如,一个switch语句。

result.Properties["memberOf"]

如果您更愿意使用文字表格,则可以存储字段的偏移量。

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

答案 2 :(得分:0)

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))

它不会像最初请求的那样生成变量名称标记,但可以用来访问不必生成名称的值。