简体   繁体   English

如何初始化作为 C 中结构元素的数组?

[英]How to initialize an array which is an element of a struct in C?

I have a struct like this in a header file.我在 header 文件中有一个这样的结构。

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

I have initialized the elements individually in another function like below.我已经在另一个 function 中单独初始化了元素,如下所示。

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

This kind of initialization works.这种初始化工作。 But I am using this in an embedded C project.但我在嵌入式 C 项目中使用它。 And I'm running into RAM issues because the struct is taking up huge size.而且我遇到了 RAM 问题,因为该结构占用了巨大的尺寸。 After searching for solutions, I found that I can place variables in ROM by making them constant.在寻找解决方案后,我发现我可以通过使变量保持不变来将变量放入 ROM 中。 But I am not able to make this struct as constant.但我无法使这个结构保持不变。 One of the ways I found was to initialize the structure as constant like below.我发现的一种方法是将结构初始化为如下所示的常量。

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

The problem is, I am not sure how to intialize the array elements.问题是,我不确定如何初始化数组元素。 Because array size in my project runs upto 100+ elements.因为我的项目中的数组大小最多可包含 100 多个元素。 I want to know if there is way I can initialize this structure and also make it a constant so that it gets stored in ROM.我想知道是否有办法可以初始化这个结构并使其成为常量,以便将其存储在 ROM 中。

Any help is appreciated:)任何帮助表示赞赏:)

You can't simply do loops while initializing constants in C.在 C 中初始化常量时不能简单地执行循环。 You should find another way to solve this problem.你应该找到另一种方法来解决这个问题。 I can suggest two solutions:我可以提出两种解决方案:

  1. Use online array generator, like this one: https://yupana-engineering.com/online-c-array-generator , or使用在线数组生成器,例如: https://yupana-engineering.com/online-c-array-generator ,或
  2. Write your own generator using BASH, Python or another scripting language which can be integrated in your build process on pre-build stage.使用 BASH、Python 或其他可以在预构建阶段集成到构建过程中的脚本语言编写您自己的生成器。

This is normally done by "hard-coding" everything.这通常是通过“硬编码”所有内容来完成的。 In case the initializers are complex, the C source for the initializers could be generated by external scripts.如果初始化程序很复杂,初始化程序的 C 源可以由外部脚本生成。

In some cases, you may be able to solve it with the pre-processor as well, but it's not an ideal tool for the task, since it makes the code hard to read.在某些情况下,您也可以使用预处理器来解决它,但它不是该任务的理想工具,因为它使代码难以阅读。 And also, in order to come up such various forms of project-specific "clever" macros, you need quite extensive C knowledge of obscure language features in combination with a "think outside the box" mindset.而且,为了提出各种 forms 项目特定的“聪明”宏,您需要相当广泛的 C 知识,并结合“跳出框框思考”的心态。

In your case for example, where you need numeric sequences, you could cook up some macros such as these:例如,在您需要数字序列的情况下,您可以编写一些宏,例如:

#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}

After which you can initialize the struct like this:之后,您可以像这样初始化结构:

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

Another such a trick would be to create a union with a macro like另一个这样的技巧是创建一个带有类似宏的联合

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

And then接着

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

You already did this the normal/typical/easy way?您已经以正常/典型/简单的方式做到了这一点?

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

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

Not sure I understand the question as you already have and have implemented the answer.不确定我是否理解您已经拥有的问题并已实施答案。

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

it is C so you just get liberal with the curly braces each major element gets its own set, although gcc didn't like the a element having its own.它是 C,因此您只需使用花括号即可,每个主要元素都有自己的集合,尽管 gcc 不喜欢具有自己的元素。

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

and that's part of the exercise, be liberal then back off if it complains.这是练习的一部分,如果它抱怨,请保持自由然后退缩。

You can see I added a test to see that the output if the first part can then be used and compiled clean.您可以看到我添加了一个测试,看看 output 如果第一部分可以使用并编译干净。 Then compare the two outputs from the second version to confirm they are the same.然后比较第二个版本的两个输出以确认它们是相同的。 (in your case or even mine the output would be pulled into the application and that is where you would test the syntax when that gets compiled, this was just a demonstration for this answer). (在您的情况下,甚至我的情况下,output 将被拉入应用程序,并且您可以在编译时测试语法,这只是此答案的演示)。

And as pointed out you already were doing a use C to init, and you can then use C to make C code...正如所指出的,您已经在使用 C 进行初始化,然后您可以使用 C 制作 C 代码...

You just put const up front of the declaration, to make it a const.您只需将 const 放在声明的前面,使其成为 const。 Since this is const you basically want/need all of the data initialized so this simple approach will work.由于这是 const 您基本上想要/需要初始化所有数据,因此这种简单的方法将起作用。 If you know though that if a = 5 then c isn't used then you can use some of the shortcuts described in other answers/comments.如果您知道如果 a = 5 则不使用 c 那么您可以使用其他答案/评论中描述的一些快捷方式。 Those ideally will generate zeros for the uninitalized items.理想情况下,这些将为未初始化的项目生成零。 Or you can just manually put zeros in there yourself, you are not saving any space in the rom all items are present, just saving space in the embedded application source code with those shortcuts.或者您可以自己手动将零放在那里,您不会在所有项目都存在的 rom 中节省任何空间,只是使用这些快捷方式在嵌入式应用程序源代码中节省空间。

For const data like this I get quite verbose, often use code to generate code, and put extra comment data in the code to make it easier to see what that data is, no need to conserve disk space for the source code.对于像这样的 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, //[        ]

(yes that header then compressed into a single bit per pixel header to conserve rom space, depended on how and where I was using it. code generated code, then more code generated more code from that code, then that code was used). (是的,header 然后压缩成每像素一位 header 以节省 ROM 空间,这取决于我使用它的方式和位置。代码生成代码,然后更多代码从该代码生成更多代码,然后使用该代码)。

You can of course manually generate the initialization data don't have to programmatically.您当然可以手动生成初始化数据,而不必以编程方式。

Note the注意

/*a*/ 
/*0*/ 

Stuff was just to make it easier to keep track of what was going on.东西只是为了更容易跟踪正在发生的事情。 Indentation really helps as well to see what is going on and you can do it that way too.缩进也确实有助于了解正在发生的事情,您也可以这样做。

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

Or a combination of both.或两者兼而有之。

Note, some compilers don't like these extra commas so you can easily remove those请注意,一些编译器不喜欢这些额外的逗号,因此您可以轻松删除它们

this这个

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

instead of代替

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

this这个

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

instead of this而不是这个

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

And you can make this as big as you have hard drive space, granted your target and a number of toolchain tools or editors cant handle infinitely large files.你可以把它做得和你有硬盘空间一样大,授予你的目标和许多工具链工具或编辑器无法处理无限大的文件。 So you will have some limits.所以你会有一些限制。 Within those limits it all scales.在这些范围内,一切都可以扩展。

If you know how to:如果您知道如何:

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

then you basically already know the answer;那你基本上已经知道答案了; just be liberal with {curly braces}.只需使用{花括号}即可。

(I am mostly just visualizing other answers/comments). (我主要只是想象其他答案/评论)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM