如何在C语言中初始化一个数组,这个数组是一个结构的元素?

问题描述 投票:0回答:1

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

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 embedded microcontroller nxp-microcontroller
1个回答
0
投票

在C语言中,你不能简单地在初始化常量时做循环,你应该找到另一种方法来解决这个问题。我可以建议两种解决方案。

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

0
投票

这通常是通过 "硬编码 "来完成的。如果初始化器很复杂,初始化器的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

0
投票

你已经用normaltypicaleasy的方法做了?

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来init,然后你可以使用C来制作C代码......。

你只是在声明前面加了const,让它成为一个const。由于这是const,你基本上希望所有的数据都被初始化,所以这种简单的方法就可以了。 如果你知道如果a=5,那么c就不用了,那么你可以使用其他答案中描述的一些快捷方式。 这些理想情况下会为未初始化的项目生成零。 或者你可以自己手动把零放进去,你并没有在rom中节省任何空间,所有的项目都是存在的,只是用这些快捷键节省了嵌入式应用源码的空间。

对于const这样的数据,我就很啰嗦了,经常用代码生成代码,并在代码中多加注释数据,以便于看清这些数据是什么,没必要为源码节省磁盘空间。

//---- 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};

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

我主要是把其他答案可视化而已)。

© www.soinside.com 2019 - 2024. All rights reserved.