有效地将可变长度数组存储到静态存储器中

时间:2016-07-21 14:05:40

标签: c arrays

我正在开发一种嵌入式系统,需要将一些预先确定的数据存储在内存中,以便在运行时使用。数据本质上是一个大的状态转换表。

例如: {1,2},{1,3},{2,3},{2,4},{2,5},{3,1}

其中:状态1可以进入状态2或3.状态2可以进入状态3,4或5.状态3仅进入状态1.

我目前正在使用" N" x 2数组 - 其中" N"是最大转换量(在本例中为3)。

这不是空间有效,有很多未使用的内存。从上面的示例中,我们将为状态1分配2个未使用的分配,为状态3分配4个未使用的分配。如果一个状态比其余状态有更多的转换,则问题会更加明显。

我当前的实现将信息存储为结构数组,其结构的格式为:

#define max_transitions 9
...
const struct state_table{
    uint16_t number;
    char len;
    uint16_t stt[max_transitions][2];
};

然后我继续定义一堆数据:

#define MAX_STATES 619
const static struct state_table SUPERVISOR[MAX_STATES] = {
{1,6,{{301,2},{410,3},{411,4},{500,5},{501,6},{604,7}}},
...
{619,5,{{301,611},{401,297},{500,619},{501,619},{602,514}}}
};

第一个元素是当前状态,第二个是长度,第三个是STT的数组。

在619个州中,大约有10个州有9个过渡。平均过渡长度为5,因此我当前的实现会产生巨大的内存浪费。

问题: 我正在寻找有关如何提高空间效率的指导。

提前致谢,

3 个答案:

答案 0 :(得分:1)

如评论中所述,这不使用VLA。你需要的是一个结构,其中最后一个元素是一个未知长度的数组。一种简单的方法是使用指针,但它会强制您拆分初始化:

const struct state_table{
    uint16_t number;
    char len;
    const uint16_t (*stt)[2]; // pointer to arrays of size 2
};

const uint16_t tst1[][2] = {{301,2},{410,3},{411,4},{500,5},{501,6},{604,7}};
...
const uint16_t tst619[][2] = {{301,611},{401,297},{500,619},{501,619},{602,514}};

const static struct state_table SUPERVISOR[MAX_STATES] = {
{1,6,tst1,
...
{619,5,tst619}
};

实际上,这就像用指向数组的指针数组替换2D数组一样,因为结构的最后一个元素只指向其他数组。

答案 1 :(得分:1)

一种可能性是将每个状态的stt成员连接到一个共享数组,并为每个状态存储一个起始偏移量。用于此的C代码可以由辅助程序生成,或者可以手动编写和维护。如果手动执行,长度和起始偏移的枚举常量将有助于保持其可维护性。这是一个例子:

struct state_table {
    uint16_t number;
    char len;
    uint16_t offset;
};

#define MAX_STATES 619

enum {
    /* number of transitions for each state */
    st_len_1 = 6,
    /* ... */
    st_len_619 = 5,
    /* starting index of transitions for each state */
    st_offset_1 = 0,
    st_offset_2 = st_offset_1 + st_len_1,
    /* ... */
    st_offset_619 = st_offset_618 + st_len_618
};

static const uint16_t TRANSITIONS[][2] = {
    /*1*/ {301, 2}, {410, 3}, {411, 4}, {500, 5}, {501, 6}, {604, 7},
    /* ... */
    /*619*/ {301, 611}, {401, 297}, {500, 619}, {501, 619}, {602, 514},
};

static const struct state_table SUPERVISOR[MAX_STATES] = {
    {1, st_len_1, st_offset_1},
    /* ... */
    {619, st_len_619, st_offset_619}
};

您可以通过省略len中的struct state_table成员并根据offset的连续元素的SUPERVISOR成员之间的差异来确定转换次数,从而节省更多空间数组。这需要SUPERVISOR数组中的额外虚拟元素来保存终止offset,并且要求连续offset成员的值严格增加。

struct state_table {
    uint16_t number;
    uint16_t offset;
};

#define MAX_STATES 619

enum {
    /* number of transitions for each state */
    st_len_1 = 6,
    /* ... */
    st_len_619 = 5,
    /* starting index of transitions for each state */
    st_offset_1 = 0,
    st_offset_2 = st_offset_1 + st_len_1,
    /* ... */
    st_offset_619 = st_offset_618 + st_len_618,
    st_offset_end = st_offset_619 + st_len_619
};

static const uint16_t TRANSITIONS[][2] = {
    /*1*/ {301, 2}, {410, 3}, {411, 4}, {500, 5}, {501, 6}, {604, 7},
    /* ... */
    /*619*/ {301, 611}, {401, 297}, {500, 619}, {501, 619}, {602, 514},
};

static const struct state_table SUPERVISOR[MAX_STATES + 1] = {
    {1, st_offset_1},
    /* ... */
    {619, st_offset_619},
    {0xffff, st_offset_end}
};

答案 2 :(得分:0)

怎么样:

FromState[0] = 0; // To States from 0 begin at index 0
FromState[1] = 3; // To States from 0 end at index 2

ToState[0] = 1
ToState[1] = 3
ToState[2] = 7

我们很快确定状态0可以转换到3个状态1,3,7。