2

My case is somehow similar to stackoverflow.com/questions/16676973 however due to lack of knowledge I cannot learn the essential lesson from it...

What I want to achieve is loading constant image data into memory at compile time (without knowing size of each image exactly) and get an array of identifiers of each image so I can access them any time I wish within code. The ideal way would be an array of pointers to beginnings of each image, however then there is a question of how I could determine the exact size of each one later on. Would the sizeof(imagedatatype) change depending on i when I call images[i]... (I guess - no. Then how?)

How I'm trying to do this looks like this:

typedef struct _imagedatatype {
    uint8_t imageId;
    uint8_t dataofoneimage[]
} imagedatatype;
const imagedatatype images [] = {
    {1,{A, ,L,O,T, ,O,F, ,C,O,N,V,E,R,T,E,D, ,I,M,A,G,E, ,D,A,T,A, ,I,N, ,H,E,X}}, 
    {2,{A, ,L,O,T, ,O,F, ,C,O,N,V,E,R,T,E,D, ,I,M,A,G,E, ,D,A,T,A, ,I,N, ,H,E,X}}
//of course, data is fake here, just for illustration purposes, normally it is 0x00, 0x0c, etc
};

Of course, it throws error, something like "Too many initializers for array ...".

Taking it all short - I feel I have a lot of errors there, mainly ideological, but as I said I'm new to C so I'm trying to learn all those complex things quickly..

Please help.

Community
  • 1
  • 1

2 Answers2

2

Unfortunately N1570 6.7.2.1.18 says:

As a special case, the last element of a structure with more than one named member may have an incomplete array type; this is called a flexible array member. In most situations, the flexible array member is ignored. In particular, the size of the structure is as if the flexible array member were omitted except that it may have more trailing padding than the omission would imply

This means that you cannot use this method as it would not be possible to calculate address of single element in array correctly.

You can get around this by separating the image data from structure:

typedef struct _imagedatatype {
    uint8_t imageId;
    size_t size;
    uint8_t const * data;
} imagedatatype;
uint8_t const img1data [] = { ... };
uint8_t const img2data [] = { ... };
const imagedatatype images [] = {
     { 1, sizeof img1data, img1data },
     { 2, sizeof img2data, img2data },
}

If you absolutely want to define image data with the structure, you could use X-macros to get around this limitation, but underlying method would still be the same. X-macros can get messy, so be warned.

user694733
  • 15,208
  • 2
  • 42
  • 68
  • Yes, I know it could be done this way and that's how I did it before, but it looked a bit awkward to me (to explicitly give a name to every single data chunk), therefore I tried to "array-ize" them, as these are going to land somewhere within memory side by side anyway, and then only pointers to heads of these structures is what I really need to know. I also know it is working very well when size of 'dataofoneimage' is known exacly. Knowing that within C almost everyting could be done, I hoped it should be easy. To my surprise it wasn't... – Dzintars Licis Nov 27 '14 at 10:55
  • @DzintarsLicis Yes, C syntax is a bit inflexible in this case. For me usually the most efficient way is to write Python script which takes the input files and outputs the .c file. This way I can also filter out any unnecessary data with it, if it's for embedded system with limited memory. – user694733 Nov 27 '14 at 12:54
0
typedef struct _imagedatatype {
    uint8_t imageId;
    uint8_t dataofoneimage[];   // you missed the trailing ; here
} imagedatatype;

dataofoneimage member here without the array size specified is a special C feature called a flexible array member (see c99, 6.7.2.1p16 for semantics). It can only be at the end of your structure declaration (what you correctly did) but it cannot be initialized at declaration time.

Use malloc to allocate this structure and assignment or copy to populate its dataofoneimage member.

ouah
  • 142,963
  • 15
  • 272
  • 331