在编译时找到数组元素的位置 [英] Find an array element position in compile time

查看:65
本文介绍了在编译时找到数组元素的位置的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

-编辑-

大家好.我有一个元素数组,在程序的所有执行过程中都不会改变,而元素在自己的数组中可以有子元素.我必须在处理数组之前准备好它.但是,因为我知道数组不会改变,所以我想将其声明为const,并在编译时准备所有内容,因此我可以丢弃整数int son_id[NUM_OF_SONS]prepare_items()函数和数组我认为声明会更清楚.

Hi all. I've got an array of elements that will not change in all the execution of the program, and where items can have sons inside the own array. I've got to prepare the array before process it. However, because I know that the array will not change, I would like to declare it as const, and prepare all of it in compile time, so I could throw away the integers int son_id[NUM_OF_SONS], prepare_items() function and the array declaration will be, in my opinion, clearer.

#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]);
}

尽管如此,我还是这样:

I've though in something like this:

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),某种预处理器指令.怎么能做到?

However, there could be about 200 elements in the array, and I need to be able to insert or delete elements in the middle of it (in compile time). So &items[1],&items[2] should be ITEM_ID(5),ITEM_ID(10), some kind of preprocessor instruction. How could achieve that?

预先感谢,对于冗长的帖子深表歉意.

Thanks in advance, and sorry for the long post.

推荐答案

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

The nearest equivalent to templates in C (that I know of) is X-Macros. I think you can achieve this result, but it will require introducing another identifier for each struct (actually it doesn't -- scroll down to the "Edit"!) which we can sync with the array by declaring these identifiers in an enum.

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

To start with, we change the initializer elements to be in the form of macro calls. For the style I prefer, the name of this macro is not important, so I'll call it _. All calls will need the same number of elements, so add an empty list where necessary. And the whole thing is wrapped in one big macro. This big macro will receive another macro as an argument which it calls for each element.

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

现在,我们可以通过定义用法宏来声明数组数据,该宏会以正确的形式为数组声明发出参数.

Now we can declare the array data by defining a usage macro that emit the arguments in the correct form for the array declaration.

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

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

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

So far we've just achieved the same result. But now it's in a more flexible form. The next step is adding the new IDs.

#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宏以说明新参数.

And adjust the CREATE_ARRAY macro to account for the new argument.

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

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

现在有趣的部分.我们创建另一个宏以将ID生成为枚举值.

Now the fun part. We make another macro to generate the IDs as enum values.

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

enum identifiers {
DATA(CREATE_IDS)
};

现在数据可以使用这些标识符对数组进行索引了.

Now the data can use these identifiers to index the array.

#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成员,因为我们的新标识符直接是所需的数组索引.

And, of course, remove the child_id member from the struct, since our new identifiers are the desired array indices, directly.

编辑.等一下.您已经有标识符.而且它们已经是独一无二的.因此,我们不需要引入新的.我们可以简单地粉碎它们!还需要__VA_ARGS__来处理子列表中可能包含的逗号.

Edit. Wait a moment. You have identifiers already. And they're already unique. So we don't need to introduce new ones. We can simply mangle them! __VA_ARGS__ is also needed to handle the possible embedded commas in the child list.

#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输出(已添加换行符):

cpp -P output (linebreaks added):

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-宏的更多信息,请参见此问题的答案 (我写了一篇:P).


For more about X-macros, see the answers to this question (one of which I wrote :P).

这篇关于在编译时找到数组元素的位置的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆