Your questions are about several different topics, but I think this is what you are trying to do:
struct Sprite {
byte timer;
byte nLength;
byte nLengthSeq[16];
byte seqLength;
bool active;
enum {
SEQ_STOP = 1,
SEQ_PLAY = 2,
SEQ_RECORD = 3,
CALIBRATION = 4
} state;
};
Sprite sprites[17]; // "struct Sprite sprites[17]" permitted, but not required
This will allow you to write:
sprites[0].state = SEQ_PLAY;
(Almost, but more on that later in this dissertation...
)
I think you wanted an array that contains 17 sprites, not an array of 17 pointers to sprites, where those sprites would be defined and created elsewhere. Right? And if one of them is "selected", you can use a pointer to one of them:
Sprite *spriteP;
void somefn()
{
spriteP = &sprites[ selected ];
spriteP->state = Sprite::CALIBRATION;
// or less common, *spriteP.state = Sprite::CALIBRATION;
// or even (*spriteP).state = Sprite::CALIBRATION;
}
Then all your code uses spriteP
, and you just change this pointer when a different sprite is selected.
Simply stated, you don't need the typedef
word. Defining the Sprite
structure (i.e., listing its members) is also a declaration (i.e., its name). The typedef
keyword is used to declare a new "type", not a new struct. It is frequently used to shorten a complicated type name or, as PaulS points out, declare a "pointer" version of another type.
As for what typedef
is not, it is not used to declare a variable nor a struct member. In this case, there's no reason for you to have another type name for that structure: Sprite
is all you need to refer to this type. Just omit the typedef
keyword.
Similarly, you do not need a typedef
for the enum
, although it is (or was) common. As you have it now, that enum
type is actually anonymous. I believe you wanted a member of that anonymous type inside your struct, and that member was called state
.
However, it is considered good practice to name your enum types, whether they are declared inside a struct or outside. In this case, I would suggest something like:
enum state_t { <-- the type name
SEQ_STOP = 1,
SEQ_PLAY = 2,
SEQ_RECORD = 3,
CALIBRATION = 4
} state; <-- also declares a variable
This may be confusing because this is really two combined statements:
enum state_t { <-- define the type called "state_t"
SEQ_STOP = 1,
SEQ_PLAY = 2,
SEQ_RECORD = 3,
CALIBRATION = 4
};
enum state_t state; <-- define a variable of that type
And, when nested in the Sprite structure:
struct Sprite {
byte timer;
byte nLength;
byte nLengthSeq[16];
byte seqLength;
bool active;
enum state_t {
SEQ_STOP = 1,
SEQ_PLAY = 2,
SEQ_RECORD = 3,
CALIBRATION = 4
};
enum state_t state; <-- a member of that type, or...
state_t state; <-- ...just this, because "enum" is optional
};
- You may have seen code that also combines a
typedef
statement with a struct
definition:
typedef struct { int X; int y; } Coord;
This is actually an anonymous struct definition combined with a typedef statement:
struct anon { int x; int y; }; // a generic struct with 2 int members
typedef struct anon Coord; // Coord is a separate name for the same struct
This is also explains why there was a compile error. Your original code...
typedef enum {
SEQ_STOP = 1,
SEQ_PLAY = 2,
SEQ_RECORD = 3,
CALIBRATION = 4
} state;
...actually does two things: (1) defines an anonymous enum with 4 choices, and (2) declares a type called state
. This is not a member, it's a type! Then when you tried to use it, the compiler basically said, "you're using a type name like it was a member name."
Anyway, if you give the enum type a name, you can declare other variables of that type:
void check_state( Sprite::state_t last_state )
{
if (spriteP->state == last_state)
sprites[0].state = Sprite::SEQ_STOP;
"But what is that extra 'Sprite::' doing in there?", you ask.
It has to do with another concept, called scoping. Because the enum was declared (and defined) inside the Sprite
definition, state_t
and the enum choices are "hidden" from casual usage. You must prefix it with the "scope" in which it was declared. That is, **Sprite::**SEQ_STOP.
PaulS makes this suggestion:
PaulS:
The definition of the enum is NOT an integral part of the struct. Move the definition outside of the struct. Create a field in the struct that is of the type the enum is defining to hold the value.
Personally, I don't mind the nested definition, because this enum appears to be a "part" of a Sprite. If there are other things in your sketch that use the same enum
choices, then I would pull it out from inside of Sprite
. If these 4 choices are unique to a Sprite, I would leave it nested.
Nesting the enum (or any type) is a good way to avoid name "collisions", and it prepares you for the object-oriented features that you may want to use later. For example, if some other library uses the word CALIBRATION, you may get compile errors. By nesting it inside Sprite
, other libraries will not force you to rename it. And if anyone decides to reuse your code, it will not force them to avoid a collision. (Namespaces are another way, but this post is already long enough!)
In the short term, pulling the enum definition out may help you understand the difference between "types" and "instances" (i.e., variables of a certain type). So if you had declared the enum
outside of the struct Sprite
, the state_t
name could have been used without the requiring the Sprite::
scope:
enum state_t {
SEQ_STOP = 1,
SEQ_PLAY = 2,
SEQ_RECORD = 3,
CALIBRATION = 4
};
struct Sprite {
byte timer;
byte nLength;
byte nLengthSeq[16];
byte seqLength;
bool active;
state_t state; <-- voilà
};
void start_rec()
{
sprite[0].state = SEQ_RECORD; <-- ditto
Clear as mud?
Cheers,
/dev