gpt4 book ai didi

c - 在编译时查找数组元素位置

转载 作者:太空宇宙 更新时间:2023-11-03 23:27:53 24 4
gpt4 key购买 nike

-- 已编辑 --

大家好。我有一个元素数组,这些元素在程序的所有执行过程中都不会改变,并且项目可以在自己的数组中有儿子。我必须在处理数组之前准备好它。但是,因为我知道数组不会改变,所以我想将它声明为 const,并在编译时准备好所有这些,这样我就可以扔掉整数 int son_id[ NUM_OF_SONS]prepare_items() 函数和数组声明在我看来会更清晰。

#include <stdlib.h>
#include <stdio.h>

#define NUM_OF_SONS 5

struct item{
int id;
char *str;
int son_id[NUM_OF_SONS];
const struct item *son[NUM_OF_SONS];
};

const struct item *find_item(int id);

static struct item items[] = {
{4, "FIRST ELEMENT"},
{5, "SECOND ELM"},
{10, "THIRD ELM"},
{15, "FATHER", {5,10}},
{0, 0 }
};

const struct item *find_item(int id){
int i;
for(i=0; items[i].str != NULL; ++i){
if(items[i].id == id) return &items[i];
}

return NULL;
}

void fill_sons(struct item *item){
int i;
for(i=0;i<NUM_OF_SONS;++i){
if(item->son_id[i]!=0)
item->son[i] = find_item(item->son_id[i]);
}
}

void prepare_items(){
int i;
for(i=0;i<sizeof(items)/sizeof(items[0]);++i){
fill_sons(&items[i]);
}
}

void print_sons(const struct item *item);

void print_item(const struct item *item){
printf("The item %d has the text %s.\n",item->id,item->str);
print_sons(item);
}

void print_sons(const struct item *item){
int i;
for(i=0;i<NUM_OF_SONS;++i){
if(NULL!=item->son[i])
print_item(item->son[i]);
}
}

int main(){
prepare_items();

print_item(&items[0]);
print_item(&items[3]);
}

虽然我有过这样的经历:

static struct item items[] = {
{4, "FIRST ELEMENT"},
{5, "SND ELM"},
{10, "THIRD ELM"},
{15, "FATHER", {&items[1],&items[2]}},
{0, 0 }
};

但是,数组中可能有大约 200 个元素,我需要能够在其中插入或删除元素(在编译时)。所以 &items[1],&items[2] 应该是 ITEM_ID(5),ITEM_ID(10),某种预处理器指令。如何实现?

提前致谢,抱歉发了这么长的帖子。

最佳答案

(据我所知)与 C 中的模板最接近的等效项是 X-Macros。我认为你可以实现这个结果,但它需要为每个结构引入另一个标识符(实际上它不需要 - 向下滚动到“编辑”!)我们可以通过以下方式与数组同步在枚举中声明这些标识符。

首先,我们将初始化元素更改为宏调用的形式。对于我喜欢的样式,这个宏的名称并不重要,所以我将其命名为 _。所有调用都需要相同数量的元素,因此在必要时添加一个空列表。整个事情都包含在一个大宏中。这个大宏将接收另一个宏作为它为每个元素调用的参数。

#define DATA(_) \
_(4, "FIRST_ELEMENT", {}) \
_(6, "SECOND_ELEMENT", {}) \
_(10, "FATHER ELEMENT", {15, 20}) \
_(15, "SON ELEMENT 1", {}) \
_(20, "SON ELEMENT 2", {}) \
_(0, NULL, {})

现在我们可以通过定义一个使用宏来声明数组数据,该宏以数组声明的正确形式发出参数。

#define CREATE_ARRAY(a, b, c) \
{a, b, c},

struct item items[] = {
DATA(CREATE_ARRAY)
}

到目前为止,我们只是取得了相同的结果。但现在它的形式更加灵活。下一步是添加新 ID。

#define DATA(_) \
_(FIRST, 4, "FIRST_ELEMENT", {}) \
_(SECOND, 6, "SECOND_ELEMENT", {}) \
_(FATHER, 10, "FATHER ELEMENT", {15, 20}) \
_(SON1, 15, "SON ELEMENT 1", {}) \
_(SON2, 20, "SON ELEMENT 2", {}) \
_(END, 0, NULL, {})

并调整 CREATE_ARRAY 宏以说明新参数。

#define CREATE_ARRAY(a, b, c, d) \
{b, c, d},

struct item items[] = {
DATA(CREATE_ARRAY)
};

现在是有趣的部分。我们创建另一个宏来生成 ID 作为枚举值。

#define CREATE_IDS(a, b, c, d) \
a,

enum identifiers {
DATA(CREATE_IDS)
};

现在数据可以使用这些标识符来索引数组。

#define DATA(_) \
_(FIRST, 4, "FIRST_ELEMENT", {}) \
_(SECOND, 6, "SECOND_ELEMENT", {}) \
_(FATHER, 10, "FATHER ELEMENT", {SON1, SON2}) \
_(SON1, 15, "SON ELEMENT 1", {}) \
_(SON2, 20, "SON ELEMENT 2", {}) \
_(END, 0, NULL, {})

当然,从结构中删除 child_id 成员,因为我们的新标识符直接是所需的数组索引。


编辑。稍等。您已经有了标识符。而且它们已经是独一无二的。所以我们不需要引入新的。我们可以简单地破坏它们!还需要 __VA_ARGS__ 来处理子列表中可能嵌入的逗号。

#define CREATE_ARRAY(a, b, ...) \
{a, b, __VA_ARGS__ },

#define ID_(x) ID ## x
#define CREATE_IDS(a, b, ...) \
ID_(a),


#define DATA(_) \
_(4, "FIRST_ELEMENT", {}) \
_(6, "SECOND_ELEMENT", {}) \
_(10, "FATHER ELEMENT", {ID15, ID20}) \
_(15, "SON ELEMENT 1", {}) \
_(20, "SON ELEMENT 2", {}) \
_(0, NULL, {})

enum identifiers {
DATA(CREATE_IDS)
};

struct item items[] = {
DATA(CREATE_ARRAY)
};

cpp -P 输出(添加换行符):

enum identifiers {
ID4, ID6, ID10, ID15, ID20, ID0,
};
struct item items[] = {
{4, "FIRST_ELEMENT", {} },
{6, "SECOND_ELEMENT", {} },
{10, "FATHER ELEMENT", {ID15, ID20} },
{15, "SON ELEMENT 1", {} },
{20, "SON ELEMENT 2", {} },
{0, NULL, {} },
};

有关 X 宏的更多信息,请参阅 this question 的答案(其中一个是我写的:P)。

关于c - 在编译时查找数组元素位置,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22721958/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com