如何初始化数组,该数组是 C 中结构的元素



我在头文件中有一个这样的结构。

typedef struct test
{
int a;
int b[10];
int c[5][6];
}testStruct;

我已经在另一个函数中单独初始化了元素,如下所示。

void foo()
{
testStruct t[2];
t[0].a = 10;
for(int i = 0; i < 10; i++)
{
t[0].b[i] = i;
}
for(int i = 0; i <5; i++)
{
for(int j =0; j < 6; j++)
{
t[0].c[i][j] = j;
}
}

这种初始化有效。但是我正在嵌入式 C 项目中使用它。而且我遇到了 RAM 问题,因为结构占用了巨大的尺寸。 在搜索解决方案后,我发现我可以通过使它们恒定来在 ROM 中放置变量。但是我无法使这个结构保持不变。我发现的方法之一是将结构初始化为常量,如下所示。

const testStruct t2 = { 0, {1,2 ..}, {3.4...} }

问题是,我不确定如何初始化数组元素。因为我项目中的数组大小最多运行 100+ 个元素。我想知道是否有办法初始化这个结构并使其成为常量,以便它存储在 ROM 中。

任何帮助都值得赞赏:)

你不能在初始化 C 中的常量时简单地执行循环。您应该找到解决此问题的另一种方法。我可以建议两个解决方案:

  1. 使用在线数组生成器,如下所示:https://yupana-engineering.com/online-c-array-generator,或
  2. 使用BASH,Python或其他脚本语言编写自己的生成器,这些脚本语言可以在预构建阶段集成到构建过程中。

这通常是通过"硬编码"所有内容来完成的。如果初始值设定项很复杂,则初始值设定项的 C 源可以由外部脚本生成。

在某些情况下,您也可以使用预处理器来解决它,但它不是完成任务的理想工具,因为它使代码难以阅读。而且,为了提出如此多样形式的特定于项目的"聪明"宏,你需要相当广泛的 C 语言知识,了解晦涩的语言功能,并结合"跳出框框思考"的思维方式。

例如,在您需要数字序列的情况下,您可以制作一些宏,例如:

#define SEQ1 0,
#define SEQ2 SEQ1 1,
#define SEQ3 SEQ2 2,
#define SEQ4 SEQ3 3,
#define SEQ5 SEQ4 4,
#define SEQ6 SEQ5 5,
#define SEQ7 SEQ6 6,
#define SEQ8 SEQ7 7,
#define SEQ9 SEQ8 8,
#define SEQ10 SEQ9 9,
#define SEQUENCE(n) {SEQ##n}

之后,您可以像这样初始化结构:

const testStruct t[2] =
{
[0] = 
{
.a = 10,
.b = SEQUENCE(10),
.c = { SEQUENCE(6),SEQUENCE(6),SEQUENCE(6),SEQUENCE(6),SEQUENCE(6) },
},
};

另一个这样的技巧是创建一个带有宏的联合,例如

#define SEQUENCE_TYPE(n) typedef union { int arr_max[10]; int arr[n]; } sequence_trick;

然后

static const sequence_trick trick = { .arr_max=(int[]){0,1,2,3,4,5,6,7,8,9} };
trick.arr // here you have a const array of length n, compile-time initialized to values 0,1,..., n

您已经以正常/典型/简单的方法执行此操作?

typedef struct test
{
int a;
int b[10];
int c[5][6];
}testStruct;
const testStruct t2 = { 0, {1,2 ..}, {3.4...} }

不确定我是否理解这个问题,因为您已经拥有并已实现答案。

#define SECOND_PASS
#include <stdio.h>
typedef struct test
{
int a;
int b[10];
int c[5][6];
}testStruct;
testStruct t[2];
#ifdef SECOND_PASS
const testStruct test[2]=
{
{/*0*/
/*a*/10,
{/*b*/0,1,2,3,4,5,6,7,8,9,},
{/*c*/
{/*0*/0,1,2,3,4,5,},
{/*1*/1,2,3,4,5,6,},
{/*2*/2,3,4,5,6,7,},
{/*3*/3,4,5,6,7,8,},
{/*4*/4,5,6,7,8,9,},
}/*c*/,
}/*0*/,
{/*1*/
/*a*/11,
{/*b*/1,2,3,4,5,6,7,8,9,10,},
{/*c*/
{/*0*/1,2,3,4,5,6,},
{/*1*/2,3,4,5,6,7,},
{/*2*/3,4,5,6,7,8,},
{/*3*/4,5,6,7,8,9,},
{/*4*/5,6,7,8,9,10,},
}/*c*/,
}/*1*/,
};
#endif
int main ( void )
{
unsigned int ra;
for(ra=0;ra<2;ra++)
{
t[ra].a = 10+ra;
for(int i = 0; i < 10; i++)
{
t[ra].b[i] = i+ra;
}
for(int i = 0; i <5; i++)
{
for(int j =0; j < 6; j++)
{
t[ra].c[i][j] = j+i+ra;
}
}
}
printf("{n");
for(ra=0;ra<2;ra++)
{
printf("{/*%d*/n",ra);
printf("/*a*/%d,n",t[ra].a);
printf("{/*b*/");
for(int i = 0; i < 10; i++)
{
printf("%d,",t[ra].b[i]);
}
printf("},n");
printf("{/*c*/n");
for(int i = 0; i < 5; i++)
{
printf("{/*%d*/",i);
for(int j = 0; j < 6; j++)
{
printf("%d,",t[ra].c[i][j]);
}
printf("},n");
}
printf("}/*c*/,n");
printf("}/*%d*/,n",ra);
}
printf("};n");
#ifdef SECOND_PASS
printf("{n");
for(ra=0;ra<2;ra++)
{
printf("{/*%d*/n",ra);
printf("/*a*/%d,n",t[ra].a);
printf("{/*b*/");
for(int i = 0; i < 10; i++)
{
printf("%d,",test[ra].b[i]);
}
printf("},n");
printf("{/*c*/n");
for(int i = 0; i < 5; i++)
{
printf("{/*%d*/",i);
for(int j = 0; j < 6; j++)
{
printf("%d,",test[ra].c[i][j]);
}
printf("},n");
}
printf("}/*c*/,n");
printf("}/*%d*/,n",ra);
}
printf("};n");
#endif
return(0);
}

它是 C,所以你只是用大括号变得自由,每个主要元素都有自己的集合,尽管 GCC 不喜欢 A 元素有自己的集合。

so.c:19:1: warning: braces around scalar initializer
{/*a*/10},

这是练习的一部分,要自由,如果抱怨,那就退缩。

您可以看到我添加了一个测试以查看输出,如果第一部分可以使用并编译干净。 然后比较第二个版本的两个输出以确认它们是相同的。 (在您的情况下,甚至是我的情况,输出将被拉入应用程序中,这就是您在编译语法时测试语法的地方,这只是此答案的演示)。

正如你所指出的,你已经在使用 C 来初始化,然后你可以使用 C 来制作 C 代码......

您只需将 const 放在声明的前面,使其成为一个 const。由于这是常量,您基本上希望/需要初始化所有数据,因此这种简单的方法将起作用。 如果您知道如果 a = 5 则不使用 c,那么您可以使用其他答案/注释中描述的一些快捷方式。 理想情况下,这些将为未初始化的项目生成零。 或者你可以自己手动把零放进去,你不会在所有项目都存在的rom中节省任何空间,只是使用这些快捷方式节省嵌入式应用程序源代码中的空间。

对于像这样的常量数据,我变得非常冗长,经常使用代码来生成代码,并在代码中放置额外的注释数据以使其更容易查看该数据是什么,无需为源代码节省磁盘空间。

//---- 30 ----
0x00,0x07,0x07,0x07,0x07,0x07,0x00,0x00, //[ #####  ]
0x07,0x07,0x00,0x00,0x07,0x07,0x07,0x00, //[##  ### ]
0x07,0x07,0x00,0x07,0x07,0x07,0x07,0x00, //[## #### ]
0x07,0x07,0x07,0x07,0x00,0x07,0x07,0x00, //[#### ## ]
0x07,0x07,0x07,0x00,0x00,0x07,0x07,0x00, //[###  ## ]
0x07,0x07,0x07,0x00,0x00,0x07,0x07,0x00, //[###  ## ]
0x00,0x07,0x07,0x07,0x07,0x07,0x00,0x00, //[ #####  ]
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, //[        ]
//---- 31 ----
0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, //[   ##   ]
0x00,0x00,0x07,0x07,0x07,0x00,0x00,0x00, //[  ###   ]
0x00,0x07,0x07,0x07,0x07,0x00,0x00,0x00, //[ ####   ]
0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, //[   ##   ]
0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, //[   ##   ]
0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, //[   ##   ]
0x00,0x07,0x07,0x07,0x07,0x07,0x07,0x00, //[ ###### ]
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, //[        ]
//---- 32 ----
0x00,0x07,0x07,0x07,0x07,0x07,0x00,0x00, //[ #####  ]
0x07,0x07,0x00,0x00,0x00,0x07,0x07,0x00, //[##   ## ]
0x00,0x00,0x00,0x00,0x00,0x07,0x07,0x00, //[     ## ]
0x00,0x00,0x00,0x07,0x07,0x07,0x00,0x00, //[   ###  ]
0x00,0x07,0x07,0x07,0x00,0x00,0x00,0x00, //[ ###    ]
0x07,0x07,0x00,0x00,0x00,0x07,0x07,0x00, //[##   ## ]
0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x00, //[####### ]
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, //[        ]

(是的,该标头然后压缩为每个像素标头的一位以节省ROM空间,这取决于我使用它的方式和位置。 代码生成代码,然后更多代码从该代码生成更多代码,然后使用该代码)。

当然,您可以手动生成初始化数据,而不必以编程方式生成。

注意

/*a*/ 
/*0*/ 

东西只是为了更容易地跟踪正在发生的事情。缩进也确实有助于查看正在发生的事情,您也可以这样做。

const testStruct test[2]=
{
{
10,
{0,1,2,3,4,5,6,7,8,9,},
{
{0,1,2,3,4,5,},
{1,2,3,4,5,6,},
{2,3,4,5,6,7,},
{3,4,5,6,7,8,},
{4,5,6,7,8,9,},
},
},
{
11,
{1,2,3,4,5,6,7,8,9,10,},
{
{1,2,3,4,5,6,},
{2,3,4,5,6,7,},
{3,4,5,6,7,8,},
{4,5,6,7,8,9,},
{5,6,7,8,9,10,},
},
},
};

或两者兼而有之。

请注意,某些编译器不喜欢这些额外的逗号,因此您可以轻松删除这些逗号

{3,4,5,6,7,8},

而不是

{3,4,5,6,7,8,},

}/*c*/,
}/*1*/
};

而不是这个

}/*c*/,
}/*1*/,
};

你可以让它和你有硬盘空间一样大,授予你的目标和许多工具链工具或编辑器无法处理无限大的文件。 所以你会有一些限制。 在这些限制范围内,它都可以扩展。

如果您知道如何:

const int x = 5;
const float y = 1.5F;
const double z = 2.1;
const char s[]="hello world";
const int a[5]={1,2,3,4,5};

那么你基本上已经知道答案了;只要用{花括号}保持自由。

(我主要只是想象其他答案/评论)。

最新更新