C 在编译时查找数组元素位置
--编辑-- 大家好。我有一个元素数组,它在程序的所有执行过程中都不会改变,在这个数组中,项可以在自己的数组中有子元素。我必须在处理阵列之前准备好它。但是,因为我知道数组不会改变,所以我想将它声明为C 在编译时查找数组元素位置,c,metaprogramming,C,Metaprogramming,--编辑-- 大家好。我有一个元素数组,它在程序的所有执行过程中都不会改变,在这个数组中,项可以在自己的数组中有子元素。我必须在处理阵列之前准备好它。但是,因为我知道数组不会改变,所以我想将它声明为const,并在编译时准备好所有内容,这样我就可以扔掉整数int-son\u-id[NUM\u-of-son],prepare\u-items()函数,我认为数组声明会更清晰 #include <stdlib.h> #include <stdio.h> #define NUM
const
,并在编译时准备好所有内容,这样我就可以扔掉整数int-son\u-id[NUM\u-of-son]
,prepare\u-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]);
}
但是,数组中可能有大约200个元素,并且我需要能够在其中间插入或删除元素(在编译时)。所以
&项[1],&items[2]
应该是项ID(5),项ID(10)
,某种预处理器指令。如何才能做到这一点
提前感谢您,并为这篇长篇大论感到抱歉。关于我所能提供的最好的信息——因为C绝对不是用来跟踪这种元数据的——是
\uuuuuuuu行
常量
\uuuuu LINE\uuuu
将当前行号插入程序,您可以将其用作结构项中的字段。显然,您还需要承诺在项
的定义中不包含任何空格,并且还需要知道项
在文件中的起始位置。对于后者,您可以执行以下操作:
int first_line = __LINE__ + 2;
const struct item items[] = {
{4, "FIRST_ELEMENT", __LINE__},
然后记得从行id
(或者你想叫它什么)字段中减去第一行
这不是一个好的解决方案,但我认为C最好不用编写代码将一个数组的内容加载到另一个数组中,并在移动过程中跟踪元数据。首先,您必须知道,一旦您将项
声明为常量项结构的数组,编写const struct item items[]时执行的操作代码>,则在初始化后将无法更改这些结构的内容
例如,您将无法在项
数组中的任何一个结构中为子
数组的任何元素分配任何内容。哇,太棒了,让我们举个代码示例:
items[2].child[0] = &( items[3] );
// or just ... items + 3;
// you won't be able to do this because items[2] is defined as a constant
我真的不明白你的目标是什么,但有一件事可能会帮助你。您可以执行以下操作:
#include <stdio.h>
#define MaximumChildCount 5 // personal preference, easier to read, change as you wish
typedef struct item{
int id;
char *str;
// I left the childs_id out, since you've implied that you'd like that out
struct item *child[MaximumChildCount];
};
int main( ){
const struct item sons[] = {
{ 15, "SON ELEMENT 1" },
{ 20, "SON ELEMENT 2" }
};
// creating sons before the parent, biologically nonsense?
// well, if you want to keep the record of child elements inside parent
// and make them all constants, then you need to have children before
const struct item items[] = {
{ 4, "FIRST_ELEMENT" },
{ 6, "SECOND_ELEMENT" },
{ 10, "FATHER ELEMENT", { sons, sons + 1 } },
// sons points to first son, sons + 1 points to the second one
// assigned them at initialization, just like you had with { 15, 20 }
{ 0, NULL }
};
printf( "%s", items[2].child[1]->str );
return 0;
}
然后在初始化过程中按如下方式分配它们:
static struct item items[] = {
{4, "FIRST ELEMENT"},
{5, "SND ELM"},
{10, "THIRD ELM"},
{15, "FATHER", {&items[1],&items[2]}},
{0, 0 }
};
... = {
...
...
{ ..., ..., { &son1, &son2 } },
...
};
如果这不是你要找的东西,我很抱歉。我真的很难理解原因。与C语言中的模板(据我所知)最接近的等价物是X宏。我认为您可以实现这一结果,但它需要为每个结构引入另一个标识符(实际上不是——向下滚动到“编辑”!),我们可以通过在枚举中声明这些标识符来与数组同步
首先,我们将初始值设定项元素更改为宏调用的形式。对于我喜欢的样式,此宏的名称并不重要,因此我将其命名为\uuu
。所有调用都需要相同数量的元素,因此在必要时添加一个空列表。整个过程都被包装在一个大宏中。这个大宏将接收另一个宏作为参数,它为每个元素调用该参数
#define DATA(_) \
_(4, "FIRST_ELEMENT", {}) \
_(6, "SECOND_ELEMENT", {}) \
_(10, "FATHER ELEMENT", {15, 20}) \
_(15, "SON ELEMENT 1", {}) \
_(20, "SON ELEMENT 2", {}) \
_(0, NULL, {})
现在,我们可以通过定义一个usage宏来声明数组数据,该宏以数组声明的正确形式发出参数
#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\u id
成员,因为我们的新标识符直接是所需的数组索引
编辑。稍等片刻您已经有了标识符。它们已经是独一无二的了。所以我们不需要引进新的。我们可以把它们弄碎<代码>\uuuu VA\u ARGS\uuuuu
也需要处理子列表中可能嵌入的逗号
#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
输出(添加换行符):
有关X宏的更多信息,请参阅答案(我写了其中一个:p)。在编译时已知数组中的项,因为它们在源代码的初始值设定项列表中的顺序相同。例如,我可以判断数组元素0
具有id号为4的项。请澄清,也许用一个你想写但不能写的代码示例。我认为OP要求的是一种独立于初始值设定项元素顺序的方式。例如,为了允许他在索引1中插入一个编号为5的项,将项5向下移动到索引2,等等。我不知道编译时的方法,所以我建议最好是一个索引数组,在运行时开始时初始化,它对项数组进行索引。例如,如果索引器指向示例项数组的索引2,则为索引10。(不存在的索引器将包含NULL)请考虑进一步解释您的问题。现在,通过查看上面的部分,在——长版本——行中,我建议执行intsearchedd=4;int i=0;虽然(items[i].id!=searchedID)如果(++i>items的大小){/*不存在*/break;}
和i
最终将是保存idsearchedID=4
的元素的索引,但我感觉所要求的并不是这么简单。也许是语言问题……对不起,我会尽量解释清楚。@DoxyLover,我不能这样做,因为id可能是,例如,50000。我不能保存一个50000长度的数组,其中99%的数组是空元素。这到底是如何解决这个问题的?他将如何利用这一点,比如说,找出什么
#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)
};
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, {} },
};