I have a struct. I also have several arrays of different lengths (stored in flash) containing instances of this struct. Is it possible to create an array of these arrays? I don't care if I have to waste some space by making all the elements the same length as the longest array. Thanks.
Is it possible, in C, to create an array of arrays of sructs?
Sure, you can do it. Sometimes the access may get confusing, with multiple levels of indirection.
Sometimes, I'll make the higher/highest level an array of pointers to the subordinate(s), rather than a full array with the subordinates. In particular, this sidesteps (at least to some extent) the storage issue with variable-length constructs.
A simple (nearly trivial) example...in this case the "character strings" (line buffers) are all the same length but wouldn't have to be.
char line1[24]; // 20-char LCD line plus a few more char line2[24]; // 20-char LCD line plus a few more char line3[24]; // 20-char LCD line plus a few more char line4[24]; // 20-char LCD line plus a few more char * flash line_ptrs[4]={line1, line2, line3, line4};
Yes.
Note that it gets a bit hairy accessing everything from Flash with the legacy PROGMEM.
If you use the new __flash modifier, the new GCC should look after this painlessly. (just like the other Compilers have done since Day One)
In practice, you either have fixed length arrays inside a struct. Or you store named arrays separately. With pointers to these named arrays/strings. I am guessing that the "variable length" means char strings.
David.
Edit. Lee has shown Codevision example. CV has always handled flash. GCC now has __flash. G++ does not have __flash.
CV has always handled flash.
And as of 3.x (or maybe 2.x), CV also will take the __flash to keep namespaces purer.
The flash or __flash keywords can be used to specify that a constant must be placed in FLASH memory, no matter what is the state of the Store Global Constants in FLASH Memory option:
flash <type definition> <identifier> = constant expression;
__flash <type definition> <identifier> = constant expression;
...
Accessing the AVR internal EEPROM is accomplished using global variables, preceded by the eeprom or __eeprom memory attributes
Thanks, but it's not working for me yet. If I initialize with:
struct Frame * Animations[3] = {loop1, loop2, loop3}; // Frame is the name of the struct, loopn is the name of the array of Frames in flash
I get a compiler error: invalid initialization type; found `pointer to __flash struct Frame' expected `pointer to struct Frame'|
If I initialize with:
struct Frame * flash Animations[3] = {loop1, loop2, loop3};
I get the same error.
If I initialize with:
struct Frame * __flash Animations[3] = {loop1, loop2, loop3};
Same error. I'm using Jumpstart C (formerly ICCAVR) which supports __flash. That's how I declare the loopn arrays.
Ah-ha. I had assumed you were using GCC.
Please post a minimal actual code. I don't have Jumpstart C. I do have CV and GCC. They should all recognise __flash keyword.
The actual position of the keyword will affect its meaning.
David.
Here are the declarations as they appear in the code (in this order):
struct Frame { unsigned char digit; // Digit: 0 = 1 minutes, 1 = 10 minutes, etc. unsigned char seg; // Segment to turn on: a - g unsigned char onoff; // 0 = segment off, 1 = segment on unsigned char dur; // Duration in msec. to maintain segment state }; __flash struct Frame loop1[] = { {0, 'a', 1, 50}, {0, 'a', 0, 50}, {0, 'b', 1, 50}, {0, 'b', 0, 50}, {0, 'c', 1, 50}, {0, 'c', 0, 50}, {0, 'd', 1, 50}, {0, 'd', 0, 50}, {1, 'd', 1, 50}, {1, 'd', 0, 50}, {2, 'd', 1, 50}, {2, 'd', 0, 50}, {3, 'd', 1, 50}, {3, 'd', 0, 50}, {3, 'e', 1, 50}, {3, 'e', 0, 50}, {3, 'f', 1, 50}, {3, 'f', 0, 50}, {3, 'a', 1, 50}, {3, 'a', 0, 50}, {2, 'a', 1, 50}, {2, 'a', 0, 50}, {1, 'a', 1, 50}, {1, 'a', 0, 50} }; __flash struct Frame loop2[] = { {0, 'a', 1, 50}, {0, 'a', 0, 50}, {0, 'b', 1, 50}, {0, 'b', 0, 50}, {0, 'c', 1, 50}, {0, 'c', 0, 50}, {0, 'd', 1, 50}, {0, 'd', 0, 50}, {1, 'd', 1, 50}, {1, 'd', 0, 50}, {2, 'd', 1, 50}, {2, 'd', 0, 50}, {3, 'd', 1, 50}, {3, 'd', 0, 50}, {3, 'e', 1, 50}, {3, 'e', 0, 50}, {3, 'f', 1, 50}, {3, 'f', 0, 50}, {3, 'a', 1, 50}, {3, 'a', 0, 50}, {2, 'a', 1, 50}, {2, 'a', 0, 50}, {1, 'a', 1, 50}, {1, 'a', 0, 50} }; __flash struct Frame loop3[] = { {0, 'a', 1, 50}, {0, 'a', 0, 50}, {0, 'b', 1, 50}, {0, 'b', 0, 50}, {0, 'c', 1, 50}, {0, 'c', 0, 50}, {0, 'd', 1, 50}, {0, 'd', 0, 50}, {1, 'd', 1, 50}, {1, 'd', 0, 50}, {2, 'd', 1, 50}, {2, 'd', 0, 50}, {3, 'd', 1, 50}, {3, 'd', 0, 50}, {3, 'e', 1, 50}, {3, 'e', 0, 50}, {3, 'f', 1, 50}, {3, 'f', 0, 50}, {3, 'a', 1, 50}, {3, 'a', 0, 50}, {2, 'a', 1, 50}, {2, 'a', 0, 50}, {1, 'a', 1, 50}, {1, 'a', 0, 50} };
Here's main(), up to where the error is thrown (just before init();):
int main(void) { char i = 0, x = 0, y, z, a; struct Frame * __flash Animations[3] = {loop1, loop2, loop3}; init();
__flash struct Frame * __flash Animations[3] = {loop1, loop2, loop3};
Woohoo! That compiles. Thanks. One more question. How do I access each loopn, as well as each element in loopn? I'm rusty with pointers.
#include <avr/io.h> struct Frame { unsigned char digit; // Digit: 0 = 1 minutes, 1 = 10 minutes, etc. unsigned char seg; // Segment to turn on: a - g unsigned char onoff; // 0 = segment off, 1 = segment on unsigned char dur; // Duration in msec. to maintain segment state }; const __flash struct Frame loop1[] = { {0, 'a', 1, 50}, {0, 'a', 0, 50}, {0, 'b', 1, 50}, {0, 'b', 0, 50}, {0, 'c', 1, 50}, {0, 'c', 0, 50}, {0, 'd', 1, 50}, {0, 'd', 0, 50}, {1, 'd', 1, 50}, {1, 'd', 0, 50}, {2, 'd', 1, 50}, {2, 'd', 0, 50}, {3, 'd', 1, 50}, {3, 'd', 0, 50}, {3, 'e', 1, 50}, {3, 'e', 0, 50}, {3, 'f', 1, 50}, {3, 'f', 0, 50}, {3, 'a', 1, 50}, {3, 'a', 0, 50}, {2, 'a', 1, 50}, {2, 'a', 0, 50}, {1, 'a', 1, 50}, {1, 'a', 0, 50} }; const __flash struct Frame loop2[] = { {0, 'a', 1, 50}, {0, 'a', 0, 50}, {0, 'b', 1, 50}, {0, 'b', 0, 50}, {0, 'c', 1, 50}, {0, 'c', 0, 50}, {0, 'd', 1, 50}, {0, 'd', 0, 50}, {1, 'd', 1, 50}, {1, 'd', 0, 50}, {2, 'd', 1, 50}, {2, 'd', 0, 50}, {3, 'd', 1, 50}, {3, 'd', 0, 50}, {3, 'e', 1, 50}, {3, 'e', 0, 50}, {3, 'f', 1, 50}, {3, 'f', 0, 50}, {3, 'a', 1, 50}, {3, 'a', 0, 50}, {2, 'a', 1, 50}, {2, 'a', 0, 50}, {1, 'a', 1, 50}, {1, 'a', 0, 50} }; const __flash struct Frame loop3[] = { {0, 'a', 1, 50}, {0, 'a', 0, 50}, {0, 'b', 1, 50}, {0, 'b', 0, 50}, {0, 'c', 1, 50}, {0, 'c', 0, 50}, {0, 'd', 1, 50}, {0, 'd', 0, 50}, {1, 'd', 1, 50}, {1, 'd', 0, 50}, {2, 'd', 1, 50}, {2, 'd', 0, 50}, {3, 'd', 1, 50}, {3, 'd', 0, 50}, {3, 'e', 1, 50}, {3, 'e', 0, 50}, {3, 'f', 1, 50}, {3, 'f', 0, 50}, {3, 'a', 1, 50}, {3, 'a', 0, 50}, {2, 'a', 1, 50}, {2, 'a', 0, 50}, {1, 'a', 1, 50}, {1, 'a', 0, 50} }; void init(void) { } int main(void) { char i = 0, x = 0, y, z, a; const struct Frame __flash *Animations[3] = {loop1, loop2, loop3}; init(); while (1) { for (int i = 0; i < 3; i++) { const struct Frame __flash *f = Animations[i]; for (int j = 0; j < 8; j++) { PORTD = f->seg; f++; } } } }
Your compiler might not be as fussy for const as GCC. But it should accept it ok.
That example rums in the Simulator.
David.
Thanks, David. I'm trying to understand this before I try to run it. Each time through the i loop, a pointer to a structure is created as a constant. This pointer, f, points to Animations[i]. Animations[] is an array of pointers to arrays of structures. f steps through each element of Animations[i] via the f++ statement in the j loop, getting incremented 8 times. Some questions:
- Why make f a constant?
- Each Animations[i] has 24 elements, so shouldn't the loop go until j == 24?
- Is incrementing f once enough to advance it to the next element of Animations[i]?
As I said, my pointer fu is weak. ;-)
Woohoo! That compiles.
Why make f a constant?
Is incrementing f once enough to advance it to the next element of Animations[i]?
Another possibility to access each element:
for (uint8_t i = 0; i < 3; i++) for (uint8_t j = 0; j < 24; j++) PORTD = Animations[i][j].seg;
The second __flash doesn't make any sense then.
From a recent thread:
https://www.avrfreaks.net/comment...
Indeed, it must be "unwound". It can make your head hurt, such as multiple levels of indirection.
Further complicated in AVR, with the multiple address spaces. As a parameter, it can be const but point to SRAM.
Toolchains vary in AVR-address-space implementation. Digest this set of CodeVision examples:
...
/* Pointer stored in FLASH to a char string placed in FLASH */
flash char * flash flash_ptr_to_flash="This string is placed in FLASH";
... [and other combinations]
This works great in my h/w, Stefan; thanks:
for (uint8_t i = 0; i < 3; i++) for (uint8_t j = 0; j < 24; j++) PORTD = Animations[i][j].seg;
It's also clearer (to me) than the other suggestion. However, it's only clear because Animations[][] looks like a "normal' two-dimensional array. In my case, there are three rows and a varying number of columns. I'd like j to step through the exact number of columns in each Animations[i], but when I calculate sizeof(Animations[i]), the result I get is 2. It seems to me it should be the number of bytes in each struct (4) x the number of elements (structs) in Animations[i], which is a lot more than 2. In fact, just executing the statement
x = sizeof(Animations[i]);
causes my code to misbehave (even if x is an int). What am I missing?
But Animations is simply
const struct Frame __flash *Animations[3] = {loop1, loop2, loop3};
So it consists of 3 pointers. In a small AVR, this would occupy 3 words (6 bytes).
Just run the Simulation in AS7. I guess that AS7 will accept code built by ImageCraft. (AS4 accepted iccavr7 and iccavr8 )
Yes, these constructions are difficult to visualise in your head. Draw a diagram with pencil and paper.
Then step through with the Simulator inspecting where the data has been stored in memory. And observe how Flash is accessed with LPM and regular SRAM is done conventionally.
Incidentally, your (and my) example show loop1, loop2, loop3 with the same size. You do not have a field to say how big anything is.
I generally use a list structure with the address of data and sizeof(data). Then any walk process knows how far it can go.
David.
Thanks, David. I'll walk through the code in the simulator (or my emulator and h/w) later when I have more time. Part of my confusion is, Animations[i][j] looks and works like like a two-dimensional array of structs, not pointers to structs since the pointer doesn't get dereferenced before accessing the seg parameter. So I assumed sizeof(Animations[i]) would return the number of bytes in the Animations[i] array, not the number of bytes in the pointer to the Animations[i] array (which I understand is 2, as my code indicates). It's still not clear to me why an array of pointers acts like an array of arrays.
As for the loopn lengths, I just copied and pasted loop1 to fill out the test data set. In practice, the loops will be different lengths, so I was hoping to use sizeof(array)/sizeof(element) to get the length of each loopn array.
It's still not clear to me why an array of pointers acts like an array of arrays.
x[i] is equivalent to *(x+i).
Fun fact: because the '+' is commutative it is also equivalent to *(i+x) and i[x]. So instead of Animations[i][j] you could also use j[Animations[i]].
Though that is useful only for confusing people. ;-)
I would make Animations slightly different e.g.
struct Frame_descriptor { Frame *film; int siz; }; const struct Frame_descriptor0 __flash *Animations[3] = { { loop1, sizeof(loop1} }, { loop2, sizeof(loop2) }, { loop3, sizeof(loop3} }, };
for (uint8_t i = 0; i < 3; i++) { int numframes = Animations[i].size / sizeof(struct Frame); for (uint8_t j = 0; j < numframes; j++) PORTD = Animations[i][j].film->seg;
Untested. Note that sizeof() always gives you bytes. Pointer arithmetic uses the size of the object. Likewise, if you want to know the number of elements in an array.
You could always make your Frame_descriptor struct use number_of_elements instead of size_in_bytes
e.g.
struct Frame_descriptor { Frame *film; int n; }; const struct Frame_descriptor0 __flash *Animations[3] = { { loop1, sizeof(loop1}/sizeof(struct Frame) }, { loop2, sizeof(loop2)/sizeof(struct Frame) }, { loop3, sizeof(loop3}/sizeof(struct Frame) }, };
David.
Thanks, David. I understand logically what you're suggesting, but my compiler doesn't.
struct Frame_descriptor { int *Frame; int n; }; int main(void) { int i = 0, x = 0, y, z, a; const struct Frame_descriptor __flash *Animations[3] = { { loop1, sizeof(loop1}/sizeof(struct Frame) }, { loop2, sizeof(loop2)/sizeof(struct Frame) }, { loop3, sizeof(loop3}/sizeof(struct Frame) }, };
On the first row of *Animations[3] (the one with loop1) it throws, "|198| syntax error; found `,' expecting `}'. I changed Frame_descriptor since the compiler wasn't accepting it the way you suggested. This seems to make more sense to me, too, though that may be part of the problem.
Sharpen your eyes (-:
You have curly braces at the end of some of the sizeof () calls. Should be closing parenthesis.
> Sharpen your eyes
Whippersnappers making fun of senior citizens! Is that what this board has come to? Screw my 59 year old eyes. I changed the font to 14.
> You have curly braces at the end of some of the sizeof () calls. Should be closing parenthesis.
Thanks for pointing that out. I chock it up to my eyes, er, font, and carelessly cutting-and-pasting.
Nevertheless, after the fix, the error remains.
I changed Frame_descriptor since the compiler wasn't accepting it the way you suggested. This seems to make more sense to me, too
First member of Frame_descriptor should be a pointer to the actual data (the arrays). Why does a pointer to int make more sense for you?
David was just a little bit sloppy and forgot a few words in front of 'Frame'.
Surely a "Frame_descriptor" should have members that point to a Frame struct.
Why would you invent some unrelated type instead?
My example was untested. Looking at your data, loop1[] has 24 members.
I suggest that you Simulate my example. And post any syntax errors.
The important point is to have correct types at all times. i.e. listen to the Compiler messages when it whinges.
David.
Whippersnappers
Thank you! (-:
I'm 2 years behind you. And have the eyesight of a mole, more or less...
Yes, Johan. But moles have got nice furry coats. Everyone wants to stroke them.
Stefan: > Why does a pointer to int make more sense for you?
Because I'm a spaz (particularly with pointers). I read my edited code as an int that pointed to a Frame. I recognize that error, but I was compelled to change Frame *film; as that drives the compiler to say, "|154| invalid struct field declarations." I didn't find the time to simulate this yesterday, and I'm going out of town in a few minutes until Sunday, so I'll pick it up again then. Thanks loads for all your help.
Stefan: > David was just a little bit sloppy and forgot a few words in front of 'Frame'.
Which words would you suggest?
I will write and test an example for you. My apologies for posting Untested code.
.
David.
Which words would you suggest?
David: > My apologies for posting Untested code.
No need to apologize. I'm grateful for any help.
Change names as desired. Insert __flash and const as needed.
Replace dots.
datum_t col0[]={ ... }; datum_t col1[]={ ... }; datum_t col2[]={ ... }; datum_t col3[]={ ... }; #define entry(col) { col, sizeof(col)/sizeof(col[0]) } struct col { datum_t *ptr; uint8_t count; } raggedbottom[]= { entry(col0), entry(col1), entry(col2), entry(col3) } ; enum { colsNum=sizeof(raggedbottom)/sizeof(raggedbottom[0] } ; ... for(j=0; j< colsNum; ++j) { struct col c=raggedbottom[j]; for(k=0; k< c.count; ++k) { stuff with c.ptr[k] } // k } // j
I didn't work hard on names.
Thanks, Skeeve. I kind of see what you're doing (cols are actually rows?), but I'm away from my computer until tomorrow, so I'll try it when I get back.
I probably messed up rows vs. cols
Unless representing a textbook matrix, I usually think in terms of array2[hi][lo].
Fortran does array2(lo, hi).
If row is always the first index we have confusion when using both.
Hi, Skeeve. I get the same error I was getting with David's code: "invalid struct field declarations" on the Frame *ptr; line below:
#define entry(loop) { loop, sizeof(loop)/sizeof(loop[0]) } struct loop { Frame *ptr; uint8_t count; } raggedbottom[]= { entry(loop1), entry(loop2), entry(loop3), } ;
Frame and loops are still defined as in my May 10, 2017 - 02:57 PM post, above.
I get the same error I was getting with David's code: "invalid struct field declarations" on the Frame *ptr; line below:
That should be a pointer to your actual data in Flash. You already had working code with an array of such pointers. Why is it a problem for you to correctly declare a single pointer of that type?
Frame and loops are still defined as in my May 10, 2017 - 02:57 PM post, above.
Please don't do that..
We don't want to stitch together code that might be the same thing you're having. It's bound to end up with us not seeing what you're seeing, and will just cause confusion. Post minimal but complete code that demonstrates the problem.
If you absolutely want to refer to another post in a thread, then do not use the timestamp. It is presented to every user based on his local timezone. I.e. in the presentation of the thread I get in my vista there is no post with a timestamp containing "02:57". Use the post number at the top right of every post as a reference. Since it is a link you can even copy that URL and use that to refer to another post (inside or outside of the thread), if you like.
__f;lash is a type qualifier, like const and volatile, but fussier.
Pointer to non-const may not point to const, but the reverse works.
__flash must match exactly:
Pointer to __flash may only point to __flash and pointer to non-__flash may only point to non-__flash.
Like const and volatile, but not PROGMEM, __flash works on typedef's.
PROGMEM objects are subjects of lies told to the compiler and are often accessed by _P functions that know better.
To summarize, I have three loopn arrays of Frame structs listed below, two are the same length and one is different. I'd like to have an Animations array containing an arbitrary number of these loopn arrays of arbitrary lengths and then select a loopn at random from Animations. Since I won't know the selected array's length, I'll need to measure it on the fly. My code so far (developed with the help of everyone in this thread; thanks) allows me to do everything I want except measure the length of each loopn (or Animations[a], below).
struct Frame { unsigned char digit; // Digit: 0 = 1 minutes, 1 = 10 minutes, etc. unsigned char seg; // Segment to turn on: a - g unsigned char onoff; // 0 = segment off, 1 = segment on unsigned char dur; // Duration in msec. to maintain segment state }; __flash struct Frame loop1[] = { {0, 'a', 1, 50}, {0, 'a', 0, 50}, {0, 'b', 1, 50}, {0, 'b', 0, 50}, {0, 'c', 1, 50}, {0, 'c', 0, 50}, {0, 'd', 1, 50}, {0, 'd', 0, 50}, {1, 'd', 1, 50}, {1, 'd', 0, 50}, {2, 'd', 1, 50}, {2, 'd', 0, 50}, {3, 'd', 1, 50}, {3, 'd', 0, 50}, {3, 'e', 1, 50}, {3, 'e', 0, 50}, {3, 'f', 1, 50}, {3, 'f', 0, 50}, {3, 'a', 1, 50}, {3, 'a', 0, 50}, {2, 'a', 1, 50}, {2, 'a', 0, 50}, {1, 'a', 1, 50}, {1, 'a', 0, 50} }; __flash struct Frame loop2[] = { {0, 'b', 1, 1}, {0, 'c', 1, 50}, {0, 'b', 0, 1}, {0, 'c', 0, 50}, {0, 'e', 1, 1}, {0, 'f', 1, 50}, {0, 'e', 0, 1}, {0, 'f', 0, 50}, {1, 'b', 1, 1}, {1, 'c', 1, 50}, {1, 'b', 0, 1}, {1, 'c', 0, 50}, {1, 'e', 1, 1}, {1, 'f', 1, 50}, {1, 'e', 0, 1}, {1, 'f', 0, 50}, {2, 'b', 1, 1}, {2, 'c', 1, 50}, {2, 'b', 0, 1}, {2, 'c', 0, 50}, {2, 'e', 1, 1}, {2, 'f', 1, 50}, {2, 'e', 0, 1}, {2, 'f', 0, 50}, {3, 'b', 1, 1}, {3, 'c', 1, 50}, {3, 'b', 0, 1}, {3, 'c', 0, 50}, {3, 'e', 1, 1}, {3, 'f', 1, 50}, {3, 'e', 0, 1}, {3, 'f', 0, 50}, }; __flash struct Frame loop3[] = { {0, 'a', 1, 50}, {0, 'a', 0, 50}, {0, 'b', 1, 50}, {0, 'b', 0, 50}, {0, 'c', 1, 50}, {0, 'c', 0, 50}, {0, 'd', 1, 50}, {0, 'd', 0, 50}, {1, 'd', 1, 50}, {1, 'd', 0, 50}, {2, 'd', 1, 50}, {2, 'd', 0, 50}, {3, 'd', 1, 50}, {3, 'd', 0, 50}, {3, 'e', 1, 50}, {3, 'e', 0, 50}, {3, 'f', 1, 50}, {3, 'f', 0, 50}, {3, 'a', 1, 50}, {3, 'a', 0, 50}, {2, 'a', 1, 50}, {2, 'a', 0, 50}, {1, 'a', 1, 50}, {1, 'a', 0, 50} }; void init(void) { }; int main(void) { int i = 0, x = 0, y, z, a; __flash struct Frame * Animations[3] = {loop1, loop2, loop3} // __flash struct Frame * __flash Animations[3] = {loop1, loop2, loop3}; // Code works this way and as in previous line init(); for (a = 0; a < 3; a++) for (y = 0; y < 5; y++) for (i = 0; i < 24; i++) { // loop2 (Animations[1]) won't play all the way through since it's longer than 24 elements if (Animations[a][i].onoff) { segSet(Animations[a][i].seg, Animations[a][i].digit); m_delay(Animations[a][i].dur); } else { segReset(Animations[a][i].seg, Animations[a][i].digit); m_delay(Animations[a][i].dur); } } while(1) ; return 0; }
There have been several suggestions that I create an additional struct to track the size of each loopn, something like this:
struct Frame_descriptor { Frame *film; int siz; }; const struct Frame_descriptor0 __flash *Animations[3] = { { loop1, sizeof(loop1} }, { loop2, sizeof(loop2) }, { loop3, sizeof(loop3} }, };
I haven't been able to test this, however, as the compiler throws an error on the Frame *film line (or Frame *ptr) in the Frame_descriptor definition: invalid struct field declarations. Stefan pointed out that *film should be a pointer to the actual data in flash, but I don't understand this comment as I thought struct definitions are just placeholders; you can't get them to store anything "actual" until you create an instance and initialize it, which you can't do if the compiler won't allow you to define it in the first place.
Anyway, this is where I am, and I really appreciate everyone's patience.
but I don't understand this comment as I thought struct definitions are just placeholders; you can't get them to store anything "actual" until you create an instance and initialize it
In
struct Frame_descriptor { Frame *film; int siz; };
film is a pointer to a struct called Frame. How can it be more exact? While Frame will be stored in flash,
struct Frame_descriptor { __flash Frame *film; int siz; }; struct Frame_descriptor { const Frame *film; int siz; };
don't compile any better.
In
struct Frame_descriptor { Frame *film; int siz; };film is a pointer to a struct called Frame.
but I don't understand this comment as I thought struct definitions are just placeholders
I would opt for the term "template" rather than "placeholder" here.
After that, lets straighten out when structs are actually created (I'll refer to such as a "struct occurence"), and when only the template is declared (I'll actually call this a "struct type" from now on). Turns out there are several variants.
Starting with just declaring a struct occurence:
struct { int i; double f; } myStruct1;
With this you have one occurence of an actual struct, and you can access it's members:
myStruct1.i = 42;
Now, you often need several structs - perhaps in different places. C has supported this as long as it has supported structs by allowing you to declare a struct type. You do that like so:
struct myStructType{ int i; double f; };
You now have this type to be used to define as many structs of that type that you wish. Or you can use this type to form an array of such. Or declare another struct (or define a struct type) with this struct type as one of its members.
But before we show how to use it, you need to knoe that the compiler keeps a completely separate namespace for such struct types. The C keyword 'struct' is actually the signal to the compiler to use that namespace (put something in it, or look for something in it). Names in the 'struct' namespace won't collide or interfere with names in the "default/unnamed namespace" (where all you other variables live). So, this is actually valid C:
struct foo { int i; double j; }; int foo;
Not that you'd want to do that. But it will work. And it illustrates the peculiarity that the 'struct' namespace is. Also, note that the above shows one type declared and one variable defined (the integer foo)!
So, now we more or less know how to define two structs of the type MyStructType. It goes:
struct MyStructType myStruct1; struct MyStructType myStruct2;
There's nothing stopping you from using a "combined effort to declare a type and define an instance at the same time, and then use the type to define two more instances.
struct myStruct4 { int i; double j; } MyStructType; struct MyStructType myStruct5; struct MyStructType myStruct6;
Again, you would probably not want to do it this way. But again, it illustrates the mechanism.
Finally, and in order to hide the somewhat messy struct namespace, we can make use of typedefs. They are like variable definitions, but will define a type. Not a 'struct type' this time, but a name of a type whose name is in the "default/unnamed namespace". Thus such typedefed names will collide with any identical variable name or other typedefed name you have already introduced.
Typedefs go like variable definitions, with the one difference that where the variable name gent there goes the type name you want to define. Like this:
typedef struct { int i; double j; } MyTypedefedStructType;
So you need to tell above that it is a struct. No way around that. The nice thing is that you now can use MyTypedefedStructType (without the 'struct' keyword prefixed) to define variable, to use as the element of an array, or as a member of another struct or struct type or typedefed struct type. Examples:
MyTypedefedStructType myStruct7; MyTypedefedStructType myStruct8; MyTypedefedStructType myArrayOfsuch[5]; typedef struct { MyTypedefedStructType s; int anotherInt; } MyTypedefedSuperStruct; MyTypedefedSuperStruct mySuperStruct; myStruct7.i = 42; myArrayOfStructs[3] = 7; mySuperStruct.s.i = 21;
The typedef approach serves us well most of the time. It removes those pesky extra compiles we must do just because we needed to add a forgotten 'struct' somewhere. It also makes things clearer.
Caveat Emptor: I typed most all of the above in without actually testing it. There might be the odd typo in those code snippets.
In C, struct Frame != Frame .
In C, struct Frame != Frame .
Can you explain the difference? In this code:
struct Frame { unsigned char digit; // Digit: 0 = 1 minutes, 1 = 10 minutes, etc. unsigned char seg; // Segment to turn on: a - g unsigned char onoff; // 0 = segment off, 1 = segment on unsigned char dur; // Duration in msec. to maintain segment state }; __flash struct Frame loop1[] = { {0, 'a', 1, 50}, {0, 'a', 0, 50}, {0, 'b', 1, 50}, {0, 'b', 0, 50}, {0, 'c', 1, 50}, {0, 'c', 0, 50}, {0, 'd', 1, 50}, {0, 'd', 0, 50}, {1, 'd', 1, 50}, {1, 'd', 0, 50}, {2, 'd', 1, 50}, {2, 'd', 0, 50}, {3, 'd', 1, 50}, {3, 'd', 0, 50}, {3, 'e', 1, 50}, {3, 'e', 0, 50}, {3, 'f', 1, 50}, {3, 'f', 0, 50}, {3, 'a', 1, 50}, {3, 'a', 0, 50}, {2, 'a', 1, 50}, {2, 'a', 0, 50}, {1, 'a', 1, 50}, {1, 'a', 0, 50} };
a struct called Frame is defined and then an array of them is declared and initialized. This works as intended, so I don't understand the difference you're highlighting.
Life is so much easier if you stick to typedefs and forget struct tags all together with the one exception when you need a struct pointer to the struct itself - then use a tag only for that.
lautman wrote:No, it is not. It is a pointer to an object of type 'Frame', but that type does not exist in your code.In
struct Frame_descriptor { Frame *film; int siz; };film is a pointer to a struct called Frame.
It's the first thing defined at the top of my code. Three arrays are initialized containing instances of it. I can access the Frame array elements, and their parameters. In what sense does the type not exist?
As others have said "struct Frame" is not the same as "Frame".
.
Really, do yourself a favor and learn to typedef.
As others have said "struct Frame" is not the same as "Frame". . Really, do yourself a favor and learn to typedef.
OK, I can do this:
typedef struct { unsigned char digit; // Digit: 0 = 1 minutes, 1 = 10 minutes, etc. unsigned char seg; // Segment to turn on: a - g unsigned char onoff; // 0 = segment off, 1 = segment on unsigned char dur; // Duration in msec. to maintain segment state } Frame; __flash Frame loop1[] = { {0, 'a', 1, 50}, {0, 'a', 0, 50}, {0, 'b', 1, 50}, {0, 'b', 0, 50}, {0, 'c', 1, 50}, {0, 'c', 0, 50}, {0, 'd', 1, 50}, {0, 'd', 0, 50}, {1, 'd', 1, 50}, {1, 'd', 0, 50}, {2, 'd', 1, 50}, {2, 'd', 0, 50}, {3, 'd', 1, 50}, {3, 'd', 0, 50}, {3, 'e', 1, 50}, {3, 'e', 0, 50}, {3, 'f', 1, 50}, {3, 'f', 0, 50}, {3, 'a', 1, 50}, {3, 'a', 0, 50}, {2, 'a', 1, 50}, {2, 'a', 0, 50}, {1, 'a', 1, 50}, {1, 'a', 0, 50} }; __flash Frame loop2[] = { {0, 'b', 1, 1}, {0, 'c', 1, 50}, {0, 'b', 0, 1}, {0, 'c', 0, 50}, {0, 'e', 1, 1}, {0, 'f', 1, 50}, {0, 'e', 0, 1}, {0, 'f', 0, 50}, {1, 'b', 1, 1}, {1, 'c', 1, 50}, {1, 'b', 0, 1}, {1, 'c', 0, 50}, {1, 'e', 1, 1}, {1, 'f', 1, 50}, {1, 'e', 0, 1}, {1, 'f', 0, 50}, {2, 'b', 1, 1}, {2, 'c', 1, 50}, {2, 'b', 0, 1}, {2, 'c', 0, 50}, {2, 'e', 1, 1}, {2, 'f', 1, 50}, {2, 'e', 0, 1}, {2, 'f', 0, 50}, {3, 'b', 1, 1}, {3, 'c', 1, 50}, {3, 'b', 0, 1}, {3, 'c', 0, 50}, {3, 'e', 1, 1}, {3, 'f', 1, 50}, {3, 'e', 0, 1}, {3, 'f', 0, 50}, }; __flash Frame loop3[] = { {0, 'a', 1, 50}, {0, 'a', 0, 50}, {0, 'b', 1, 50}, {0, 'b', 0, 50}, {0, 'c', 1, 50}, {0, 'c', 0, 50}, {0, 'd', 1, 50}, {0, 'd', 0, 50}, {1, 'd', 1, 50}, {1, 'd', 0, 50}, {2, 'd', 1, 50}, {2, 'd', 0, 50}, {3, 'd', 1, 50}, {3, 'd', 0, 50}, {3, 'e', 1, 50}, {3, 'e', 0, 50}, {3, 'f', 1, 50}, {3, 'f', 0, 50}, {3, 'a', 1, 50}, {3, 'a', 0, 50}, {2, 'a', 1, 50}, {2, 'a', 0, 50}, {1, 'a', 1, 50}, {1, 'a', 0, 50} }; typedef struct { Frame *film; int n; } Frame_descriptor; void init(void) { }; int main(void) { int i = 0, x = 0, y, z, a; __flash Frame_descriptor *Animations[3] = { { loop1, sizeof(loop1)/sizeof(Frame) }, { loop2, sizeof(loop2)/sizeof(Frame) }, { loop3, sizeof(loop3)/sizeof(Frame) }, }; init();
but then the compiler says, "syntax error; found `,' expecting `}'," on the line beginning with loop1 in the *Animations array.
Thanks for the lengthy explanation, sternst. As clawson advised, I'll stick with typdefs, though it's not solving my problem yet.
but then the compiler says, "syntax error; found `,' expecting `}'," on the line beginning with loop1 in the *Animations array.
No other errors or warnings?
lautman wrote:but then the compiler says, "syntax error; found `,' expecting `}'," on the line beginning with loop1 in the *Animations array.No other errors or warnings?
Oh, there are plenty more. I tend to just focus on the first one, though. Here's the rest (the Animations array is defined from lines 206 - 210):
|207| syntax error; found `,' expecting `}'| |207| skipping `,' `sizeof' `(' `loop1' `)' `/' `sizeof' `(' ... up to `}'| |207| invalid initialization type; found `pointer to __flash Frame' expected `pointer to __flash Frame_descriptor'| |208| syntax error; found `,' expecting `}'| |208| skipping `,' `sizeof' `(' `loop2' `)' `/' `sizeof' `(' ... up to `}'| |208| invalid initialization type; found `pointer to __flash Frame' expected `pointer to __flash Frame_descriptor'| |209| syntax error; found `,' expecting `}'| |209| skipping `,' `sizeof' `(' `loop3' `)' `/' `sizeof' `(' ... up to `}'| |209| invalid initialization type; found `pointer to __flash Frame' expected `pointer to __flash Frame_descriptor'| |224| unknown field `onoff' of `Frame_descriptor'| |225| unknown field `seg' of `Frame_descriptor'| |225| unknown field `digit' of `Frame_descriptor'| |226| unknown field `dur' of `Frame_descriptor'| |229| unknown field `seg' of `Frame_descriptor'| |229| unknown field `digit' of `Frame_descriptor'| |230| unknown field `dur' of `Frame_descriptor'| |866|[warning] missing return value|
but then the compiler says, "syntax error; found `,' expecting `}'," on the line beginning with loop1 in the *Animations array.
You made Animations an array of pointers, but the initialization data are no pointers.
BTW:
Thanks for the lengthy explanation, sternst.